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.
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
@@ -1,73 +1,58 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
2
 
3
3
  describe IB::Models::Execution do # AKA IB::Execution
4
4
 
5
- let(:properties) do
5
+ let(:props) do
6
6
  {:account_name => "DU111110",
7
- :average_price => 1.31075,
8
7
  :client_id => 1111,
9
- :cumulative_quantity => 20000,
10
8
  :exchange => "IDEALPRO",
11
9
  :exec_id => "0001f4e8.4f5d48f1.01.01",
12
- :liquidation => 0,
10
+ :liquidation => true,
13
11
  :order_id => 373,
14
- :perm_id => 1695693613,
12
+ :perm_id => 1695693619,
15
13
  :price => 1.31075,
14
+ :average_price => 1.31075,
16
15
  :shares => 20000,
16
+ :cumulative_quantity => 20000,
17
17
  :side => :buy,
18
18
  :time => "20120312 15:41:09"
19
19
  }
20
20
  end
21
21
 
22
- context "instantiation" do
23
- context 'empty without properties' do
24
- subject { IB::Execution.new }
25
-
26
- it { should_not be_nil }
27
- its(:order_id) { should == 0 }
28
- its(:client_id) { should == 0 }
29
- its(:perm_id) { should == 0 }
30
- its(:shares) { should == 0 }
31
- its(:price) { should == 0 }
32
- its(:liquidation) { should == 0 }
33
- its(:created_at) { should be_a Time }
34
- end
22
+ let(:human) do
23
+ "<Execution: 20120312 15:41:09 buy 20000 at 1.31075 on IDEALPRO, " +
24
+ "cumulative 20000 at 1.31075, ids 373/1695693619/0001f4e8.4f5d48f1.01.01>"
25
+ end
35
26
 
36
- context 'with properties' do
37
- subject { IB::Execution.new properties }
27
+ let(:defaults) do
28
+ {:order_id => 0,
29
+ :client_id => 0,
30
+ :perm_id => 0,
31
+ :shares=> 0,
32
+ :price => 0,
33
+ :liquidation => false,
34
+ :created_at => Time,
35
+ }
36
+ end
38
37
 
39
- it 'sets properties right' do
40
- properties.each do |name, value|
41
- subject.send(name).should == value
42
- end
43
- end
44
- end
45
- end #instantiation
38
+ let(:errors) do
39
+ {:side=>["should be buy/sell/short"],
40
+ :cumulative_quantity=>["is not a number"],
41
+ :average_price=>["is not a number"]}
42
+ end
46
43
 
47
- context "properties" do
44
+ let(:assigns) do
45
+ {:side =>
46
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
47
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell},
48
48
 
49
- it 'allows setting properties' do
50
- expect {
51
- x = IB::Execution.new
52
- properties.each do |name, value|
53
- subject.send("#{name}=", value)
54
- subject.send(name).should == value
55
- end
56
- }.to_not raise_error
57
- end
49
+ [:shares, :cumulative_quantity, :price, :average_price] =>
50
+ {[:foo, 'BAR', nil] => /is not a number/},
58
51
 
59
- it 'sets side as directed by its setter' do
60
- @x = IB::Execution.new
61
- ['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b].each do |val|
62
- expect { @x.side = val }.to_not raise_error
63
- @x.side.should == :buy
64
- end
52
+ :liquidation => {[1, true] => true, [0, false] => false},
53
+ }
54
+ end
65
55
 
66
- ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S].each do |val|
67
- expect { @x.side = val }.to_not raise_error
68
- @x.side.should == :sell
69
- end
70
- end
71
- end # properties
56
+ it_behaves_like 'Model'
72
57
 
73
58
  end # describe IB::Models::Contract
@@ -0,0 +1,127 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::Contracts::Option do # AKA IB::Option
4
+
5
+ let(:props) do
6
+ {:symbol => 'AAPL',
7
+ :expiry => '201301',
8
+ :strike => 600,
9
+ :right => :put,
10
+ }
11
+ end
12
+
13
+ let(:human) do
14
+ "<Option: AAPL 201301 put 600 SMART >"
15
+ end
16
+
17
+ let(:defaults) do
18
+ {:sec_type => :option,
19
+ :con_id => 0,
20
+ :strike => 0,
21
+ :min_tick => 0,
22
+ :include_expired => false,
23
+ :created_at => Time,
24
+ }
25
+ end
26
+
27
+ let(:errors) do
28
+ {:right => ["should be put or call"],
29
+ :strike => ["must be greater than 0"],
30
+ }
31
+ end
32
+
33
+ let(:assigns) do
34
+ {:expiry =>
35
+ {[200609, '200609'] => '200609',
36
+ [20060913, '20060913'] => '20060913',
37
+ [:foo, 2006, 42, 'bar'] => /should be YYYYMM or YYYYMMDD/},
38
+
39
+ :sec_type =>
40
+ {['OPT', :option] => :option,
41
+ IB::CODES[:sec_type].reject { |k, v,| k == :option }.to_a =>
42
+ /should be an option/},
43
+
44
+ :right =>
45
+ {["PUT", "put", "P", "p", :put] => :put,
46
+ ["CALL", "call", "C", "c", :call] => :call,
47
+ ['', '0', '?', :none, :foo, 'BAR', 42] => /should be put or call/},
48
+
49
+ :exchange =>
50
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
51
+ [:smart, 'SMART', 'smArt'] => 'SMART'},
52
+
53
+ :primary_exchange =>
54
+ {[:cboe, 'cboE', 'CBOE'] => 'CBOE',
55
+ [:SMART, 'SMART'] => /should not be SMART/},
56
+
57
+ :symbol =>
58
+ {['AAPL', :AAPL] => 'AAPL'},
59
+
60
+ :local_symbol =>
61
+ {['AAPL 130119C00500000', :'AAPL 130119C00500000'] =>
62
+ 'AAPL 130119C00500000',
63
+ 'BAR'=> /invalid OSI code/},
64
+
65
+ :strike => {[0, -30.0] => /must be greater than 0/},
66
+
67
+ :multiplier => {['123', 123] => 123},
68
+
69
+ [:under_con_id, :min_tick, :coupon] => {123 => 123}
70
+
71
+ }
72
+ end
73
+
74
+ context 'using shorter class name without properties' do
75
+ subject { IB::Models::Option.new }
76
+ it_behaves_like 'Model instantiated empty'
77
+ end
78
+
79
+ context 'using shortest class name without properties' do
80
+ subject { IB::Option.new }
81
+ it_behaves_like 'Model instantiated empty'
82
+ end
83
+
84
+ it_behaves_like 'Model'
85
+ it_behaves_like 'Self-equal Model'
86
+
87
+ context 'properly initiated' do
88
+ subject { IB::Option.new props }
89
+ it_behaves_like 'Contract'
90
+
91
+ it 'has extra osi accessor, aliasing :local_symbol' do
92
+ subject.osi = 'FOO'
93
+ subject.local_symbol.should == 'FOO'
94
+ subject.local_symbol = 'bar'
95
+ subject.osi.should == 'bar'
96
+ end
97
+ end
98
+
99
+ it 'correctly defines Contract type (sec_type) for Option contract' do
100
+ [IB::Contract.new(:sec_type => :option),
101
+ IB::Contract.new(:sec_type => 'OPT'),
102
+ IB::Option.new
103
+ ].each do |contract|
104
+ contract.should_not be_bag
105
+ contract.should_not be_bond
106
+ contract.should_not be_stock
107
+ contract.should be_option
108
+ end
109
+ end
110
+
111
+ context '.from_osi class builder' do
112
+ subject { IB::Option.from_osi 'AAPL130119C00500000' }
113
+
114
+ it 'builds a valid Option contract from OSI code' do
115
+ subject.should be_an IB::Option
116
+ subject.should be_valid
117
+ subject.symbol.should == 'AAPL'
118
+ subject.expiry.should == '130118' # <- NB: Change in date!
119
+ subject.right.should == :call
120
+ subject.strike.should == 500
121
+ #subject.osi.should == 'AAPL 130119C00500000'
122
+ end
123
+
124
+ it_behaves_like 'Contract'
125
+ end
126
+
127
+ end # describe IB::Contract
@@ -1,116 +1,137 @@
1
- require 'spec_helper'
1
+ require 'model_helper'
2
2
 
3
3
  describe IB::Models::Order do
4
4
 
5
- let(:properties) do
6
- {:outside_rth => true,
7
- :open_close => 'C',
8
- :origin => IB::Order::Origin_Firm,
9
- :transmit => false,
5
+ let(:props) do
6
+ {:order_id => 23,
7
+ :order_ref => 'Test',
8
+ :client_id => 1111,
9
+ :perm_id => 173276893,
10
+ :parent_id => 0,
11
+ :side => :buy,
12
+ :order_type => :market_if_touched,
13
+ :limit_price => 0.01,
14
+ :total_quantity => 100,
15
+ :tif => :good_till_cancelled,
16
+ :open_close => :close,
17
+ :oca_group => '',
18
+ :oca_type => :reduce_no_block,
19
+ :origin => :firm,
10
20
  :designated_location => "WHATEVER",
11
21
  :exempt_code => 123,
12
- :delta_neutral_order_type => "HACK",
22
+ :delta_neutral_order_type => :market,
23
+ #:commission_currency => "USD",
24
+ #:status => 'PreSubmitted',
25
+ :transmit => false,
26
+ :outside_rth => true,
13
27
  :what_if => true,
14
28
  :not_held => true}
15
29
  end
16
30
 
17
- context "instantiation" do
18
- context 'empty without properties' do
19
- subject { IB::Order.new }
20
-
21
- it { should_not be_nil }
22
- its(:outside_rth) { should == false }
23
- its(:open_close) { should == "O" }
24
- its(:origin) { should == IB::Order::Origin_Customer }
25
- its(:transmit) { should == true }
26
- its(:designated_location) { should == '' }
27
- its(:exempt_code) { should == -1 }
28
- its(:delta_neutral_order_type) { should == '' }
29
- its(:what_if) { should == false }
30
- its(:not_held) { should == false }
31
- its(:created_at) { should be_a Time }
32
- end
31
+ # TODO: :presents => { Object => "Formatted"}
32
+ let(:human) do
33
+ "<Order: Test MIT GTC buy 100 New 0.01 #23/173276893 from 1111>"
34
+ end
33
35
 
34
- context 'with properties' do
35
- subject { IB::Order.new properties }
36
+ let(:defaults) do
37
+ {:outside_rth => false,
38
+ :open_close => :open,
39
+ :short_sale_slot => :default,
40
+ :tif => :day,
41
+ :order_type => :limit,
42
+ :origin => :customer,
43
+ :transmit => true,
44
+ :designated_location => '',
45
+ :exempt_code => -1,
46
+ :what_if => false,
47
+ :not_held => false,
48
+ :status => 'New',
49
+ :created_at => Time,
50
+ }
51
+ end
36
52
 
37
- it 'sets properties right' do
38
- properties.each do |name, value|
39
- subject.send(name).should == value
40
- end
41
- end
53
+ let(:errors) do
54
+ {:side =>["should be buy/sell/short"],
55
+ :order_id => ["is not a number"], }
56
+ end
42
57
 
43
- context 'essential properties are still set, even if not given explicitely' do
44
- its(:created_at) { should be_a Time }
45
- end
46
- end
58
+ let(:assigns) do
59
+ {[:order_type, :delta_neutral_order_type] => codes_and_values_for(:order_type),
60
+ :open_close =>
61
+ {['SAME', 'same', 'S', 's', :same, 0, '0'] => :same,
62
+ ['OPEN', 'open', 'O', 'o', :open, 1, '1'] => :open,
63
+ ['CLOSE', 'close', 'C', 'c', :close, 2, '2'] => :close,
64
+ ['UNKNOWN', 'unknown', 'U', 'u', :unknown, 3, '3'] => :unknown,
65
+ [42, nil, 'Foo', :bar] => /should be same.open.close.unknown/},
66
+
67
+ :side =>
68
+ {['BOT', 'BUY', 'Buy', 'buy', :BUY, :BOT, :Buy, :buy, 'B', :b] => :buy,
69
+ ['SELL', 'SLD', 'Sel', 'sell', :SELL, :SLD, :Sell, :sell, 'S', :S] => :sell,
70
+ ['SSHORT', 'Short', 'short', :SHORT, :short, 'T', :T] => :short,
71
+ ['SSHORTX', 'Shortextemt', 'shortx', :short_exempt, 'X', :X] => :short_exempt,
72
+ [1, nil, 'ASK', :foo] => /should be buy.sell.short/, },
73
+
74
+ [:what_if, :not_held, :outside_rth, :hidden, :transmit, :block_order, :sweep_to_fill,
75
+ :override_percentage_constraints, :all_or_none, :etrade_only, :firm_quote_only,
76
+ :opt_out_smart_routing, :scale_auto_reset, :scale_random_percent
77
+ ] => {[1, true] => true, [0, false] => false},
78
+ }
79
+ end
47
80
 
48
- it 'allows setting attributes' do
49
- x = IB::Order.new
50
- properties.each do |name, value|
51
- subject.send("#{name}=", value)
52
- subject.send(name).should == value
53
- end
54
- end
55
- end #instantiation
81
+ it_behaves_like 'Model'
82
+ it_behaves_like 'Self-equal Model'
56
83
 
57
84
  context 'equality' do
58
- subject { IB::Order.new properties }
85
+ subject { IB::Order.new props }
59
86
 
60
- it 'is self-equal ' do
61
- should == subject
62
- end
63
-
64
- it 'is equal to Order with the same properties' do
65
- should == IB::Order.new(properties)
66
- end
87
+ it_behaves_like 'Self-equal Model'
67
88
 
68
89
  it 'is not equal for Orders with different limit price' do
69
90
  order1 = IB::Order.new :total_quantity => 100,
70
- :limit_price => 1,
71
- :action => 'BUY'
91
+ :limit_price => 1,
92
+ :action => 'BUY'
72
93
 
73
94
  order2 = IB::Order.new :total_quantity => 100,
74
- :limit_price => 2,
75
- :action => 'BUY'
95
+ :limit_price => 2,
96
+ :action => 'BUY'
76
97
  order1.should_not == order2
77
98
  order2.should_not == order1
78
99
  end
79
100
 
80
101
  it 'is not equal for Orders with different total_quantity' do
81
102
  order1 = IB::Order.new :total_quantity => 20000,
82
- :limit_price => 1,
83
- :action => 'BUY'
103
+ :limit_price => 1,
104
+ :action => 'BUY'
84
105
 
85
106
  order2 = IB::Order.new :total_quantity => 100,
86
- :action => 'BUY',
87
- :limit_price => 1
107
+ :action => 'BUY',
108
+ :limit_price => 1
88
109
  order1.should_not == order2
89
110
  order2.should_not == order1
90
111
  end
91
112
 
92
113
  it 'is not equal for Orders with different action/side' do
93
114
  order1 = IB::Order.new :total_quantity => 100,
94
- :limit_price => 1,
95
- :action => 'SELL'
115
+ :limit_price => 1,
116
+ :action => 'SELL'
96
117
 
97
118
  order2 = IB::Order.new :total_quantity => 100,
98
- :action => 'BUY',
99
- :limit_price => 1
119
+ :action => 'BUY',
120
+ :limit_price => 1
100
121
  order1.should_not == order2
101
122
  order2.should_not == order1
102
123
  end
103
124
 
104
125
  it 'is not equal for Orders with different order_type' do
105
126
  order1 = IB::Order.new :total_quantity => 100,
106
- :limit_price => 1,
107
- :action => 'BUY',
108
- :order_type => 'LMT'
127
+ :limit_price => 1,
128
+ :action => 'BUY',
129
+ :order_type => 'LMT'
109
130
 
110
131
  order2 = IB::Order.new :total_quantity => 100,
111
- :action => 'BUY',
112
- :limit_price => 1,
113
- :order_type => 'MKT'
132
+ :action => 'BUY',
133
+ :limit_price => 1,
134
+ :order_type => 'MKT'
114
135
  order1.should_not == order2
115
136
  order2.should_not == order1
116
137
  end
@@ -0,0 +1,55 @@
1
+ require 'model_helper'
2
+
3
+ describe IB::Models::OrderState do
4
+
5
+ let(:props) do
6
+ {:order_id => 23,
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(:defaults) do
34
+ {:created_at => Time,
35
+ }
36
+ end
37
+
38
+ let(:errors) do
39
+ {:order_id => ["is not a number"],
40
+ :client_id => ["is not a number"],
41
+ :perm_id => ["is not a number"], }
42
+ end
43
+
44
+ let(:assigns) do
45
+ { :tester => {1 => 1},
46
+ [:order_id, :perm_id, :client_id] =>
47
+ {[:foo, 'bar'] => /is not a number/,
48
+ [5.0, 2006.17] => /must be an integer/, }
49
+ }
50
+ end
51
+
52
+ it_behaves_like 'Model'
53
+ it_behaves_like 'Self-equal Model'
54
+
55
+ end # describe IB::Order