ib-ruby 0.7.12 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -203,3 +203,9 @@ describe "Request Contract Info", :connected => true, :integration => true do
203
203
  end
204
204
  end # Request Forex data
205
205
  end # Contract Data
206
+
207
+
208
+ __END__
209
+ ContractData messages v.6 and 8 identical:
210
+ 10-8-500-GOOG-OPT-20130118-500-C-SMART-USD-GOOG 130119C00500000-GOOG-GOOG-81032967-0.05-100-ACTIVETIM,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,COND,CONDORDER,DAY,DEACT,DEACTDIS,DEACTEOD,FOK,GAT,GTC,GTD,GTT,HID,ICE,IOC,LIT,LMT,MIT,MKT,MTL,NONALGO,OCA,PAON,POSTONLY,RELSTK,SCALE,SCALERST,SMARTSTG,STP,STPLMT,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,VOLAT,WHATIF,-SMART,AMEX,BATS,BOX,CBOE,CBOE2,IBSX,ISE,MIBSX,NASDAQOM,PHLX,PSE-1-30351181-GOOGLE INC-CL A--201301-Communications-Internet-Web Portals/ISP-EST-20120428:CLOSED;20120430:0930-1600-20120428:CLOSED;20120430:0930-1600-
211
+ 10-6-500-GOOG-OPT-20130118-500-C-SMART-USD-GOOG 130119C00500000-GOOG-GOOG-81032967-0.01-100-ACTIVETIM,ADJUST,ALERT,ALGO,ALLOC,AON,AVGCOST,BASKET,COND,CONDORDER,DAY,DEACT,DEACTDIS,DEACTEOD,FOK,GAT,GTC,GTD,GTT,HID,ICE,IOC,LIT,LMT,MIT,MKT,MTL,NONALGO,OCA,PAON,POSTONLY,RELSTK,SCALE,SCALERST,SMARTSTG,STP,STPLMT,TRAIL,TRAILLIT,TRAILLMT,TRAILMIT,VOLAT,WHATIF,-SMART,AMEX,BATS,BOX,CBOE,CBOE2,IBSX,ISE,MIBSX,NASDAQOM,PHLX,PSE-1-30351181-GOOGLE INC-CL A--201301-Communications-Internet-Web Portals/ISP-EST-20120428:CLOSED;20120430:0930-1600-20120428:CLOSED;20120430:0930-1600-
@@ -4,8 +4,8 @@ require 'combo_helper'
4
4
  def define_contracts
5
5
  @ib = IB::Connection.new OPTS[:connection].merge(:logger => mock_logger)
6
6
  @contracts = {
7
- :stock => IB::Symbols::Stocks[:wfc],
8
- :butterfly => butterfly('GOOG', '201301', 'CALL', 500, 510, 520)
7
+ :stock => IB::Symbols::Stocks[:wfc],
8
+ :butterfly => butterfly('GOOG', '201301', 'CALL', 500, 510, 520)
9
9
  }
10
10
  close_connection
11
11
  end
@@ -19,13 +19,12 @@ describe 'Attached Orders', :connected => true, :integration => true do
19
19
 
20
20
  # Testing different combinations of Parent + Attached Orders:
21
21
  [
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
25
- [:butterfly, 10, 'DAY', 'LMT', 0.05, 1.0], # Combo Parent + target
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
28
-
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
25
+ [:butterfly, 10, 'DAY', 'LMT', 0.05, 1.0], # Combo Parent + target
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
29
28
  ].each do |(contract, qty, tif, attach_type, limit_price, attach_price, aux_price)|
30
29
  context "#{tif} BUY (#{contract}) limit order with attached #{attach_type} SELL" do
31
30
  let(:contract_type) { contract }
@@ -38,10 +37,10 @@ describe 'Attached Orders', :connected => true, :integration => true do
38
37
  #p [contract, qty, tif, attach_type, limit_price, attach_price, aux_price]
39
38
  @contract = @contracts[contract]
40
39
  place_order @contract,
41
- :total_quantity => qty,
42
- :limit_price => limit_price,
43
- :tif => tif,
44
- :transmit => false
40
+ :total_quantity => qty,
41
+ :limit_price => limit_price,
42
+ :tif => tif,
43
+ :transmit => false
45
44
 
46
45
  @ib.wait_for :OpenOrder, :OrderStatus, 2
47
46
  end
@@ -56,12 +55,12 @@ describe 'Attached Orders', :connected => true, :integration => true do
56
55
  context "Attaching #{attach_type} order" do
57
56
  before(:all) do
58
57
  @attached_order = IB::Order.new :limit_price => attach_price,
59
- :aux_price => aux_price || 0,
60
- :total_quantity => qty,
61
- :side => :sell,
62
- :tif => tif,
63
- :order_type => attach_type,
64
- :parent_id => @local_id_placed
58
+ :aux_price => aux_price || 0,
59
+ :total_quantity => qty,
60
+ :side => :sell,
61
+ :tif => tif,
62
+ :order_type => attach_type,
63
+ :parent_id => @local_id_placed
65
64
 
66
65
  @local_id_attached = @ib.place_order @attached_order, @contract
67
66
  @local_id_after = @ib.next_local_id
@@ -82,3 +82,4 @@ describe "Combo Order", :connected => true, :integration => true, :slow => true
82
82
  end # Limit
83
83
  end # Combo Orders
84
84
 
85
+ __END__
@@ -1,5 +1,48 @@
1
1
  require 'order_helper'
2
2
 
3
+ def commission_report_should_be status=:with_pnl, exec=@ib.received[:ExecutionData].last.execution
4
+ msg = @ib.received[:CommissionReport].find { |msg| msg.exec_id == exec.exec_id }
5
+ msg.should_not be_nil
6
+ msg.should be_an IB::Messages::Incoming::CommissionReport
7
+
8
+ msg.exec_id.should == exec.exec_id
9
+ msg.commission.should == 2.5 # Fixed commission for Forex
10
+ msg.currency.should == 'USD'
11
+ msg.yield.should be_nil
12
+ msg.yield_redemption_date.should == 0 # no date, YYYYMMDD format for bonds
13
+
14
+ if status == :with_pnl
15
+ msg.realized_pnl.should be_a Float
16
+ msg.realized_pnl.should be < 10000 # Not Double.MAX_VALUE
17
+ else
18
+ msg.realized_pnl.should be_nil
19
+ end
20
+ end
21
+
22
+ def execution_should_be side, opts={}
23
+ msg = @ib.received[:ExecutionData][opts[:index] || -1]
24
+ msg.request_id.should == (opts[:request_id] || -1)
25
+ msg.contract.should == @contract
26
+
27
+ exec = msg.execution
28
+ exec.perm_id.should be_an Integer
29
+ exec.perm_id.should == @ib.received[:OpenOrder].last.order.perm_id if @ib.received?(:OpenOrder)
30
+ exec.client_id.should == OPTS[:connection][:client_id]
31
+ exec.local_id.should be_an Integer
32
+ exec.local_id.should == @order.local_id if @order
33
+ exec.exec_id.should be_a String
34
+ exec.time.should =~ /\d\d:\d\d:\d\d/
35
+ exec.account_name.should == OPTS[:connection][:account_name]
36
+ exec.exchange.should == 'IDEALPRO'
37
+ exec.side.should == side
38
+ exec.shares.should == 20000
39
+ exec.cumulative_quantity.should == 20000
40
+ exec.price.should be > 1
41
+ exec.price.should be < 2
42
+ exec.price.should == exec.average_price
43
+ exec.liquidation.should == false
44
+ end
45
+
3
46
  describe "Trades", :connected => true, :integration => true, :slow => true do
4
47
 
5
48
  before(:all) { verify_account }
@@ -21,7 +64,7 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
21
64
  :total_quantity => 20000,
22
65
  :limit_price => 2,
23
66
  :action => 'BUY'
24
- #:what_if => true
67
+ #:what_if => true
25
68
 
26
69
  @ib.wait_for(5, :ExecutionData, :OpenOrder) do
27
70
  @ib.received[:OpenOrder].last &&
@@ -57,6 +100,12 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
57
100
  it 'receives OrderStatus with fill details' do
58
101
  status_should_be 'Filled'
59
102
  end
103
+
104
+ it 'also receives Commission Reports' do
105
+ @ib.received[:CommissionReport].should have_exactly(1).report
106
+
107
+ commission_report_should_be :no_pnl, @ib.received[:ExecutionData].last.execution
108
+ end
60
109
  end # Placing BUY
61
110
 
62
111
  context "Placing SELL order" do
@@ -99,6 +148,12 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
99
148
  it 'receives OrderStatus with fill details' do
100
149
  status_should_be 'Filled'
101
150
  end
151
+
152
+ it 'also receives Commission Reports' do
153
+ @ib.received[:CommissionReport].should have_exactly(1).report
154
+
155
+ commission_report_should_be :with_pnl, @ib.received[:ExecutionData].last.execution
156
+ end
102
157
  end # Placing SELL
103
158
 
104
159
  context "Request executions" do
@@ -124,9 +179,34 @@ describe "Trades", :connected => true, :integration => true, :slow => true do
124
179
  end
125
180
 
126
181
  it 'receives Execution Data' do
182
+ execution_should_be :buy, :index => 0, :request_id => 456
127
183
  execution_should_be :sell, :request_id => 456
128
184
  end
185
+
186
+ it 'also receives Commission Reports' do
187
+ @ib.received[:CommissionReport].should have_exactly(2).reports
188
+
189
+ commission_report_should_be :no_pnl, @ib.received[:ExecutionData].first.execution
190
+ commission_report_should_be :with_pnl, @ib.received[:ExecutionData].last.execution
191
+ end
192
+
129
193
  end # Request executions
130
194
  end # Forex order
131
195
 
132
196
  end # Trades
197
+
198
+ __END__
199
+
200
+ Actual message exchange for "Request executions" (TWS 925):
201
+ 10:57:41:348 <- 7-3-456-1111--20120430 10:57:31-----
202
+ 10:57:41:349 -> 11-9-456-1-12087792-EUR-CASH--0.0--IDEALPRO-USD-EUR.USD-0001f4e8.4f9dbb0b.01.01-20120430 10:57:36-DU118180-IDEALPRO-BOT-20000-1.32540-474073463-1111-0-20000-1.32540--
203
+ 10:57:41:350 -> 11-9-456-2-12087792-EUR-CASH--0.0--IDEALPRO-USD-EUR.USD-0001f4e8.4f9dbb0c.01.01-20120430 10:57:36-DU118180-IDEALPRO-SLD-20000-1.32540-474073464-1111-0-20000-1.32540--
204
+ 10:57:41:350 -> 59-1-0001f4e8.4f9dbb0b.01.01-2.5-USD-1.7976931348623157E308-1.7976931348623157E308--
205
+ 10:57:41:350 -> 59-1-0001f4e8.4f9dbb0c.01.01-2.5-USD-27.7984-1.7976931348623157E308--
206
+ 10:57:41:351 -> 55-1-456-
207
+
208
+ Actual message exchange for "Request executions" (TWS 923):
209
+ 11:11:45:436 <- 7-3-456-1111--20120430 11:11:36-----
210
+ 11:11:45:439 -> 11-8-456-1-12087792-EUR-CASH--0.0--IDEALPRO-USD-EUR.USD-0001f4e8.4f9dbc96.01.01-20120430 11:11:43-DU118180-IDEALPRO-BOT-20000-1.32485-308397342-1111-0-20000-1.32485--
211
+ 11:11:45:439 -> 11-8-456-2-12087792-EUR-CASH--0.0--IDEALPRO-USD-EUR.USD-0001f4e8.4f9dbc9a.01.01-20120430 11:11:45-DU118180-IDEALPRO-SLD-20000-1.32480-308397343-1111-0-20000-1.32480--
212
+ 11:11:45:439 -> 55-1-456-
data/spec/order_helper.rb CHANGED
@@ -219,26 +219,3 @@ def order_should_be status, order=@order
219
219
  msg.contract.should == @contract
220
220
  end
221
221
 
222
- def execution_should_be side, opts={}
223
- msg = @ib.received[:ExecutionData][opts[:index] || -1]
224
- msg.request_id.should == (opts[:request_id] || -1)
225
- msg.contract.should == @contract
226
-
227
- exec = msg.execution
228
- exec.perm_id.should be_an Integer
229
- exec.perm_id.should == @ib.received[:OpenOrder].last.order.perm_id if @ib.received?(:OpenOrder)
230
- exec.client_id.should == OPTS[:connection][:client_id]
231
- exec.local_id.should be_an Integer
232
- exec.local_id.should == @order.local_id if @order
233
- exec.exec_id.should be_a String
234
- exec.time.should =~ /\d\d:\d\d:\d\d/
235
- exec.account_name.should == OPTS[:connection][:account_name]
236
- exec.exchange.should == 'IDEALPRO'
237
- exec.side.should == side
238
- exec.shares.should == 20000
239
- exec.cumulative_quantity.should == 20000
240
- exec.price.should be > 1
241
- exec.price.should be < 2
242
- exec.price.should == exec.average_price
243
- exec.liquidation.should == false
244
- end
data/spec/spec_helper.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  require 'rspec'
2
2
  require 'ib-ruby'
3
3
 
4
- # Top level metadata for test suite level hacking
4
+ PORT ||= 4001 # 4001 for Gateway, 7496 for TWS GUI
5
+
6
+ # Top (test suite) level metadata
5
7
  OPTS ||= {
6
8
  :verbose => false, #true, # Verbosity of test outputs
7
9
  :brokertron => false, # Use mock (Brokertron) instead of paper account
@@ -20,7 +22,7 @@ else
20
22
  {:account_name => 'DU118180', # Your IB PAPER ACCOUNT, tests will only run against it
21
23
  :client_id => 1111, # Just an arbitrary id
22
24
  :host => '10.211.55.2', # Where your TWS/gateway is located, likely '127.0.0.1'
23
- :port => 4001, # 4001 for Gateway, 7496 for TWS GUI
25
+ :port => PORT,
24
26
  :reuters => true # Subscription to Reuters data enabled ?
25
27
  }
26
28
  end
data/spec/tws.rb ADDED
@@ -0,0 +1,4 @@
1
+ puts 'To run specs against TWS (not default Gateway) port, use:'
2
+ puts '$ rspec -rtws spec'
3
+
4
+ PORT = 7496