ib-ruby 0.7.3 → 0.7.4

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.
Files changed (53) hide show
  1. data/HISTORY +4 -0
  2. data/README.md +60 -30
  3. data/TODO +1 -0
  4. data/VERSION +1 -1
  5. data/bin/account_info +1 -4
  6. data/bin/cancel_orders +0 -3
  7. data/bin/contract_details +2 -5
  8. data/bin/depth_of_market +1 -4
  9. data/bin/fa_accounts +22 -0
  10. data/bin/historic_data +1 -4
  11. data/bin/historic_data_cli +0 -4
  12. data/bin/list_orders +2 -6
  13. data/bin/market_data +1 -4
  14. data/bin/option_data +2 -5
  15. data/bin/place_combo_order +17 -22
  16. data/bin/place_order +6 -10
  17. data/bin/tick_data +6 -9
  18. data/bin/time_and_sales +2 -5
  19. data/lib/ib-ruby/connection.rb +10 -5
  20. data/lib/ib-ruby/messages/incoming/open_order.rb +15 -13
  21. data/lib/ib-ruby/messages/incoming/ticks.rb +1 -1
  22. data/lib/ib-ruby/messages/incoming.rb +18 -18
  23. data/lib/ib-ruby/messages/outgoing.rb +2 -2
  24. data/lib/ib-ruby/messages.rb +3 -7
  25. data/lib/ib-ruby/models/{contract → contracts}/bag.rb +5 -8
  26. data/lib/ib-ruby/models/contracts/contract.rb +296 -0
  27. data/lib/ib-ruby/models/{contract → contracts}/option.rb +2 -4
  28. data/lib/ib-ruby/models/contracts.rb +27 -0
  29. data/lib/ib-ruby/models/execution.rb +1 -1
  30. data/lib/ib-ruby/models/order.rb +6 -17
  31. data/lib/ib-ruby/models.rb +9 -7
  32. data/lib/ib-ruby/symbols/forex.rb +50 -50
  33. data/lib/ib-ruby/symbols/futures.rb +47 -47
  34. data/lib/ib-ruby/symbols/options.rb +23 -23
  35. data/lib/ib-ruby/symbols/stocks.rb +14 -14
  36. data/lib/ib-ruby.rb +17 -9
  37. data/spec/README.md +6 -0
  38. data/spec/account_helper.rb +1 -1
  39. data/spec/combo_helper.rb +31 -0
  40. data/spec/ib-ruby/models/combo_leg_spec.rb +4 -4
  41. data/spec/ib-ruby/models/contract_spec.rb +37 -26
  42. data/spec/ib-ruby/models/execution_spec.rb +5 -5
  43. data/spec/ib-ruby/models/order_spec.rb +16 -16
  44. data/spec/integration/contract_info_spec.rb +8 -10
  45. data/spec/integration/historic_data_spec.rb +1 -1
  46. data/spec/integration/market_data_spec.rb +5 -5
  47. data/spec/integration/orders/attached_spec.rb +87 -0
  48. data/spec/integration/orders/combo_spec.rb +52 -65
  49. data/spec/integration/orders/placement_spec.rb +8 -8
  50. data/spec/order_helper.rb +97 -28
  51. data/spec/spec_helper.rb +2 -2
  52. metadata +12 -5
  53. data/lib/ib-ruby/models/contract.rb +0 -308
data/HISTORY CHANGED
@@ -149,3 +149,7 @@
149
149
  == 0.7.3 / 2012-03-23
150
150
 
151
151
  * Connection API extended
152
+
153
+ == 0.7.4 / 2012-04-04
154
+
155
+ * Order equality bug fixed
data/README.md CHANGED
@@ -13,59 +13,89 @@ You've been warned.
13
13
 
14
14
  This code is not sanctioned or supported by Interactive Brokers.
15
15
 
16
- ## REQUIREMENTS:
16
+ ## SUMMARY:
17
17
 
18
- Either the Interactive Brokers [TWS](http://www.interactivebrokers.com/en/p.php?f=tws) or
19
- [Gateway](http://www.interactivebrokers.com/en/p.php?f=programInterface&ib_entity=llc)
20
- software must be installed and configured to allow API connections from the computer
21
- you plan to run ib-ruby on, which is typically localhost if you're running ib-ruby on
22
- the same machine as TWS.
18
+ This is a pure Ruby implementation of Interactive Brokers API. It is NOT a wrapper
19
+ for a Java or C++ API, but rather uses socket API directly. So it does not have any
20
+ dependencies other than TWS/Gateway itself.
23
21
 
24
- As a rule of thumb, most recent version of ib-ruby gem only supports latest versions
25
- of TWS/Gateway API. Older versions of API are supported by previous gem versions:
22
+ Why Ruby? Many people are put off by the amount of boilerplate code/plumbing required
23
+ by Java, ActiveX or C++ API to do even the simplest of things, like getting account
24
+ data and placing/monitoring orders. This library intends to keep all the fluff away
25
+ and let you focus on writing your business logics, rather than useless boilerplate.
26
26
 
27
- ib-ruby gem TWS version API version
27
+ No more endless definitions of obligatory methods you'd never need, no spaghetti code
28
+ to divide your execution flow between multiple callbacks and interfaces.
28
29
 
29
- 0.5.21 918-920 965
30
- 0.6.1 921-923 966
31
- 0.7.1+ 924+ 967
30
+ Instead, a very simple paradigm is offered: your code interacts with the server
31
+ (TWS or Gateway) via exchange of messages. You subscribe to the server messages
32
+ that you're interested in, and send messages to server that request specific data
33
+ from it. You wait for specific messages being received, or other conditions you
34
+ define. The execution flow is under your control, rather than delegated somewhere.
35
+
36
+ Using this clear paradigm, you can hack together a simple automation of your
37
+ daily TWS-related routine in just a couple of minutes. Alternatively, you can
38
+ create a mechanical trading system with complex order processing logics, that
39
+ contains 1/10th of code and is 500% more maintaineable than it is possible with
40
+ other API implementations. The choice is yours.
32
41
 
33
42
  ## INSTALLATION:
34
43
 
35
44
  ### From RubyGems
36
45
 
37
- $ sudo gem install ib-ruby
46
+ $ sudo gem install ib-ruby [-v version]
38
47
 
39
48
  ### From Source
40
49
 
41
50
  $ git clone https://github.com/ib-ruby/ib-ruby
42
51
  $ cd ib-ruby; rake gem:install
43
52
 
53
+ ## PREREQUISITES:
54
+
55
+ 1. Install Interactive Brokers connectivity software: either
56
+ [TWS](http://www.interactivebrokers.com/en/p.php?f=tws) or
57
+ [Gateway](http://www.interactivebrokers.com/en/p.php?f=programInterface&ib_entity=llc)
58
+
59
+ 2. Configure the software to allow API connections from the computer you plan to run
60
+ ib-ruby on, which is typically localhost (127.0.0.1) if you're running ib-ruby on
61
+ the same machine as TWS/Gateway. [Here](http://www.youtube.com/watch?v=53tmypRq5wI)
62
+ you can see how this is done for TWS.
63
+
64
+ 3. Make sure sure your ib-ruby gem version is compatible with your software version.
65
+ As a rule of thumb, most recent ib-ruby gem only supports latest versions of
66
+ TWS/Gateway API. Older versions of API are supported by previous gem versions:
67
+
68
+ | ib-ruby gem | TWS version | API version |
69
+ |:------------|------------:|:------------:|
70
+ | 0.5.21 | 918-920 | 965 |
71
+ | 0.6.1 | 921-923 | 966 |
72
+ | 0.7.1+ | 924+ | 967 |
73
+
74
+
75
+ 4. Start Interactive Broker's Trader Work Station or Gateway before your code
76
+ attempts to connect to it. Note that TWS and Gateway listen to different ports,
77
+ this library assumes connection to Gateway on the same machine (localhost:4001)
78
+ by default, this can be changed via :host and :port options given to IB::Connection.new.
79
+
44
80
  ## SYNOPSIS:
45
81
 
46
- First, start up Interactive Broker's Trader Work Station or Gateway.
47
- Make sure it is configured to allow API connections on localhost.
48
- Note that TWS and Gateway listen to different ports, this library assumes
49
- connection to Gateway (localhost:4001) by default, this can changed via :host
50
- and :port options given to IB::Connection.new.
82
+ This is an example of your script that requests and prints out account data, then
83
+ places limit order to buy 100 lots of WFC and waits for execution. All in about ten
84
+ lines of code - and without sacrificing code readability or flexibility.
51
85
 
52
86
  require 'ib-ruby'
53
87
 
54
- ib = IB::Connection.new :port => 7496 # TWS on localhost
88
+ ib = IB::Connection.new :port => 7496
55
89
  ib.subscribe(:Alert, :AccountValue) { |msg| puts msg.to_human }
56
90
  ib.send_message :RequestAccountData
57
91
  ib.wait_for :AccountDownloadEnd
58
92
 
59
93
  ib.subscribe(:OpenOrder) { |msg| puts "Placed: #{msg.order}!" }
60
94
  ib.subscribe(:ExecutionData) { |msg| puts "Filled: #{msg.execution}!" }
61
- contract = IB::Models::Contract.new :symbol => 'WFC',
62
- :exchange => 'NYSE'
63
- :currency => 'USD',
64
- :sec_type => IB::SECURITY_TYPES[:stock]
65
- buy_order = IB::Models::Order.new :total_quantity => 100,
66
- :limit_price => 21.00,
67
- :action => 'BUY',
68
- :order_type => 'LMT'
95
+ contract = IB::Contract.new :symbol => 'WFC', :exchange => 'NYSE',
96
+ :currency => 'USD', :sec_type => 'STK'
97
+ buy_order = IB::Order.new :total_quantity => 100, :limit_price => 21.00,
98
+ :action => 'BUY', :order_type => 'LMT'
69
99
  ib.place_order buy_order, contract
70
100
  ib.wait_for :ExecutionData
71
101
 
@@ -74,8 +104,8 @@ TWS are called 'Outgoing', messages your code receives from TWS - 'Incoming'.
74
104
 
75
105
  First, you need to subscribe to incoming message types you're interested in
76
106
  using `Connection#subscribe`. The code block (or proc) given to `#subscribe`
77
- will be executed when an incoming message of the requested type is received
78
- from TWS, with the received message as its argument.
107
+ will be executed when an incoming message of the this type is received from TWS,
108
+ with the received message as its argument.
79
109
 
80
110
  Then, you request specific data from TWS using `Connection#send_message` or place
81
111
  your order using `Connection#place_order`. TWS will respond with messages that you
@@ -86,7 +116,7 @@ In order to give TWS time to respond, you either run a message processing loop o
86
116
  just wait until Connection receives the messages type you requested.
87
117
 
88
118
  See `lib/ib-ruby/messages` for a full list of supported incoming/outgoing messages
89
- and their attributes. The original TWS docs and code samples can be found
119
+ and their attributes. The original TWS docs and code samples can also be found
90
120
  in `misc` directory.
91
121
 
92
122
  The sample scripts in `bin` directory provide examples of how common tasks
data/TODO CHANGED
@@ -16,6 +16,7 @@ http://finance.groups.yahoo.com/group/TWSAPI/message/25413
16
16
 
17
17
  7. Create integration tests for more use cases (spec/README)
18
18
 
19
+ 8. Move Float values to Decimal (roundoff errors showed in spec!)
19
20
 
20
21
  Done:
21
22
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.3
1
+ 0.7.4
data/bin/account_info CHANGED
@@ -3,11 +3,8 @@
3
3
  # This script connects to IB API, subscribes to account info and prints out
4
4
  # messages received from IB (update every 3 minute or so)
5
5
 
6
- require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
9
-
10
6
  require 'rubygems'
7
+ require 'pathname'
11
8
  require 'bundler/setup'
12
9
  require 'ib-ruby'
13
10
 
data/bin/cancel_orders CHANGED
@@ -6,9 +6,6 @@
6
6
 
7
7
  require 'rubygems'
8
8
  require 'pathname'
9
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
10
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
11
-
12
9
  require 'bundler/setup'
13
10
  require 'ib-ruby'
14
11
 
data/bin/contract_details CHANGED
@@ -1,12 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script gets details for specific symbol from IB
4
-
5
- require 'pathname'
6
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
7
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
3
+ # This script gets details for specific contract from IB
8
4
 
9
5
  require 'rubygems'
6
+ require 'pathname'
10
7
  require 'bundler/setup'
11
8
  require 'ib-ruby'
12
9
 
data/bin/depth_of_market CHANGED
@@ -3,11 +3,8 @@
3
3
  # This script connects to IB API and subscribes to L2 (depth of market) data for
4
4
  # specific symbols
5
5
 
6
- require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
9
-
10
6
  require 'rubygems'
7
+ require 'pathname'
11
8
  require 'bundler/setup'
12
9
  require 'ib-ruby'
13
10
 
data/bin/fa_accounts ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This script receives Financial Adviser and Managed Accounts info
4
+
5
+ require 'rubygems'
6
+ require 'pathname'
7
+ require 'bundler/setup'
8
+ require 'ib-ruby'
9
+
10
+ # First, connect to IB TWS.
11
+ ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
12
+
13
+ # Subscribe to TWS alerts/errors and FA/managed account info
14
+ ib.subscribe(:Alert, :ManagedAccounts, :ReceiveFA) { |msg| puts msg.to_human }
15
+
16
+ ib.send_message :RequestFA
17
+ ib.send_message :RequestManagedAccounts
18
+
19
+ ib.wait_for :Alert
20
+
21
+ puts "\n******** Press <Enter> to cancel... *********\n\n"
22
+ STDIN.gets
data/bin/historic_data CHANGED
@@ -2,11 +2,8 @@
2
2
  #
3
3
  # This script downloads historic data for specific symbols from IB
4
4
 
5
- require 'pathname'
6
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
7
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
8
-
9
5
  require 'rubygems'
6
+ require 'pathname'
10
7
  require 'bundler/setup'
11
8
  require 'ib-ruby'
12
9
 
@@ -6,10 +6,6 @@ require 'time'
6
6
  require 'pathname'
7
7
  require 'getopt/long'
8
8
  require 'bundler/setup'
9
-
10
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
11
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
12
-
13
9
  require 'ib-ruby'
14
10
 
15
11
  include Getopt
data/bin/list_orders CHANGED
@@ -1,12 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script connects to IB API, subscribes to account info and prints out
4
- # messages received from IB (update every 3 minute or so)
3
+ # This script retrieves list of all Orders from TWS
5
4
 
6
5
  require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
9
-
10
6
  require 'rubygems'
11
7
  require 'bundler/setup'
12
8
  require 'pp'
@@ -23,7 +19,7 @@ ib.subscribe(:Alert, :OrderStatus, :OpenOrderEnd) { |msg| puts msg.to_human }
23
19
  ib.subscribe(:OpenOrder) do |msg|
24
20
  @counter += 1
25
21
  puts "#{@counter}: #{msg.to_human}"
26
- pp msg.order
22
+ #pp msg.order
27
23
  end
28
24
 
29
25
  ib.send_message :RequestAllOpenOrders
data/bin/market_data CHANGED
@@ -2,11 +2,8 @@
2
2
  #
3
3
  # This script connects to IB API and subscribes to market data for specific symbols
4
4
 
5
- require 'pathname'
6
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
7
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
8
-
9
5
  require 'rubygems'
6
+ require 'pathname'
10
7
  require 'bundler/setup'
11
8
  require 'ib-ruby'
12
9
 
data/bin/option_data CHANGED
@@ -1,12 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script connects to IB API and subscribes to market data for specific symbols
4
-
5
- require 'pathname'
6
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
7
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
3
+ # This script subscribes to market data for a list of Options
8
4
 
9
5
  require 'rubygems'
6
+ require 'pathname'
10
7
  require 'bundler/setup'
11
8
  require 'ib-ruby'
12
9
 
@@ -1,13 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script connects to IB API, subscribes to account info and prints out
4
- # messages received from IB (update every 3 minute or so)
5
-
6
- require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
3
+ # This script places GOOG option butterfly combo order
9
4
 
10
5
  require 'rubygems'
6
+ require 'pathname'
11
7
  require 'bundler/setup'
12
8
  require 'ib-ruby'
13
9
 
@@ -17,10 +13,10 @@ def butterfly symbol, expiry, right, *strikes
17
13
 
18
14
  legs = strikes.zip([1, -2, 1]).map do |strike, weight|
19
15
  # Create contract
20
- contract = IB::Models::Contract::Option.new :symbol => symbol,
21
- :expiry => expiry,
22
- :right => right,
23
- :strike => strike
16
+ contract = IB::Option.new :symbol => symbol,
17
+ :expiry => expiry,
18
+ :right => right,
19
+ :strike => strike
24
20
  # Find out contract's con_id
25
21
  @ib.clear_received :ContractData, :ContractDataEnd
26
22
  @ib.send_message :RequestContractData, :id => strike, :contract => contract
@@ -28,19 +24,18 @@ def butterfly symbol, expiry, right, *strikes
28
24
  con_id = @ib.received[:ContractData].last.contract.con_id
29
25
 
30
26
  # Create Comboleg from con_id and weight
31
- IB::Models::ComboLeg.new :con_id => con_id, :weight => weight
27
+ IB::ComboLeg.new :con_id => con_id, :weight => weight
32
28
  end
33
29
 
34
30
  # Create new Combo contract
35
- IB::Models::Contract::Bag.new :symbol => symbol,
36
- :currency => "USD", # Only US options in combo Contracts
37
- :exchange => "SMART",
38
- :legs => legs
31
+ IB::Bag.new :symbol => symbol,
32
+ :currency => "USD", # Only US options in combo Contracts
33
+ :exchange => "SMART",
34
+ :legs => legs
39
35
  end
40
36
 
41
-
42
37
  # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
43
- ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
38
+ @ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
44
39
 
45
40
  # Subscribe to TWS alerts/errors and order-related messages
46
41
  @ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
@@ -50,14 +45,14 @@ ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
50
45
  combo = butterfly 'GOOG', '201301', 'CALL', 500, 510, 520
51
46
 
52
47
  # Create Order stub
53
- order = IB::Models::Order.new :total_quantity => 10, # 10 butterflies
54
- :limit_price => 0.01, # at 0.01 x 100 USD per contract
55
- :action => 'BUY',
56
- :order_type => 'LMT'
48
+ order = IB::Order.new :total_quantity => 10, # 10 butterflies
49
+ :limit_price => 0.01, # at 0.01 x 100 USD per contract
50
+ :action => 'BUY',
51
+ :order_type => 'LMT'
57
52
 
58
53
  @ib.place_order order, combo
59
54
 
60
55
  @ib.wait_for [:OpenOrder, 3], [:OrderStatus, 2]
61
56
 
62
57
  puts "\n******** Press <Enter> to cancel... *********\n\n"
63
- STDIN.gets
58
+ gets
data/bin/place_order CHANGED
@@ -1,13 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script connects to IB API, subscribes to account info and prints out
4
- # messages received from IB (update every 3 minute or so)
5
-
6
- require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
3
+ # This script places WFC buy order for 100 lots
9
4
 
10
5
  require 'rubygems'
6
+ require 'pathname'
11
7
  require 'bundler/setup'
12
8
  require 'ib-ruby'
13
9
 
@@ -18,10 +14,10 @@ ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
18
14
  ib.subscribe(:Alert, :OpenOrder, :OrderStatus) { |msg| puts msg.to_human }
19
15
 
20
16
  wfc = IB::Symbols::Stocks[:wfc]
21
- buy_order = IB::Models::Order.new :total_quantity => 100,
22
- :limit_price => 1 + rand().round(2),
23
- :action => 'BUY',
24
- :order_type => 'LMT'
17
+ buy_order = IB::Order.new :total_quantity => 100,
18
+ :limit_price => 1 + rand().round(2),
19
+ :action => 'BUY',
20
+ :order_type => 'LMT'
25
21
  ib.wait_for :NextValidId
26
22
  ib.place_order buy_order, wfc
27
23
 
data/bin/tick_data CHANGED
@@ -2,19 +2,16 @@
2
2
 
3
3
  # This script reproduces https://github.com/ib-ruby/ib-ruby/issues/12
4
4
 
5
- require 'pathname'
6
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
7
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
8
-
9
5
  require 'rubygems'
6
+ require 'pathname'
10
7
  require 'bundler/setup'
11
8
  require 'ib-ruby'
12
9
 
13
- contract = IB::Models::Contract.new :symbol=> 'AAPL',
14
- :exchange=> "Smart",
15
- :currency=> "USD",
16
- :sec_type=> IB::SECURITY_TYPES[:stock],
17
- :description=> "Some stock"
10
+ contract = IB::Contract.new :symbol=> 'AAPL',
11
+ :exchange=> "Smart",
12
+ :currency=> "USD",
13
+ :sec_type=> IB::SECURITY_TYPES[:stock],
14
+ :description=> "Some stock"
18
15
 
19
16
  # First, connect to IB TWS. Arbitrary :client_id is used to identify your script
20
17
  ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
data/bin/time_and_sales CHANGED
@@ -1,13 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
  #
3
- # This script connects to IB API and subscribes to market data for specific symbols.
3
+ # This script connects to IB API and subscribes to market data for Forex symbols.
4
4
  # It then prints out all trades that exceed certain size.
5
5
 
6
- require 'pathname'
7
- LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
8
- $LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
9
-
10
6
  require 'rubygems'
7
+ require 'pathname'
11
8
  require 'bundler/setup'
12
9
  require 'ib-ruby'
13
10
 
@@ -277,20 +277,25 @@ module IB
277
277
  # Place Order (convenience wrapper for send_message :PlaceOrder).
278
278
  # Assigns client_id and order_id fields to placed order. Returns assigned order_id.
279
279
  def place_order order, contract
280
- send_message :PlaceOrder,
281
- :order => order,
282
- :contract => contract,
283
- :id => @next_order_id
284
280
  order.client_id = server[:client_id]
285
281
  order.order_id = @next_order_id
286
282
  @next_order_id += 1
283
+ modify_order order, contract
284
+ end
285
+
286
+ # Modify Order (convenience wrapper for send_message :PlaceOrder). Returns order_id.
287
+ def modify_order order, contract
288
+ send_message :PlaceOrder,
289
+ :order => order,
290
+ :contract => contract,
291
+ :order_id => order.order_id
287
292
  order.order_id
288
293
  end
289
294
 
290
295
  # Cancel Orders by their ids (convenience wrapper for send_message :CancelOrder).
291
296
  def cancel_order *order_ids
292
297
  order_ids.each do |order_id|
293
- send_message :CancelOrder, :id => order_id.to_i
298
+ send_message :CancelOrder, :order_id => order_id.to_i
294
299
  end
295
300
  end
296
301
 
@@ -106,14 +106,14 @@ module IB
106
106
  # Never happens! 28 is the max supported version currently
107
107
  # As of client v.55, we receive orderComboLegs (price) in openOrder
108
108
  [29, [:contract, :legs, :array, proc do |_|
109
- Models::ComboLeg.new :con_id => socket.read_int,
110
- :ratio => socket.read_int,
111
- :action => socket.read_string,
112
- :exchange => socket.read_string,
113
- :open_close => socket.read_int,
114
- :short_sale_slot => socket.read_int,
115
- :designated_location => socket.read_string,
116
- :exempt_code => socket.read_int
109
+ IB::ComboLeg.new :con_id => socket.read_int,
110
+ :ratio => socket.read_int,
111
+ :action => socket.read_string,
112
+ :exchange => socket.read_string,
113
+ :open_close => socket.read_int,
114
+ :short_sale_slot => socket.read_int,
115
+ :designated_location => socket.read_string,
116
+ :exempt_code => socket.read_int
117
117
  end],
118
118
 
119
119
  # Order keeps received leg prices in a separate Array for some reason ?!
@@ -167,17 +167,19 @@ module IB
167
167
 
168
168
  [:order, :what_if, :boolean],
169
169
  [:order, :status, :string],
170
- [:order, :init_margin, :string],
171
- [:order, :maint_margin, :string],
172
- [:order, :equity_with_loan, :string],
170
+
171
+ # IB uses weird String with Java Double.MAX_VALUE to indicate no value here
172
+ [:order, :init_margin, :decimal_max], # :string],
173
+ [:order, :maint_margin, :decimal_max], # :string],
174
+ [:order, :equity_with_loan, :decimal_max], # :string],
173
175
  [:order, :commission, :decimal_max], # May be nil!
174
176
  [:order, :min_commission, :decimal_max], # May be nil!
175
177
  [:order, :max_commission, :decimal_max], # May be nil!
176
178
  [:order, :commission_currency, :string],
177
179
  [:order, :warning_text, :string]
178
180
 
179
- @order = Models::Order.new @data[:order]
180
- @contract = Models::Contract.build @data[:contract]
181
+ @order = IB::Order.new @data[:order]
182
+ @contract = IB::Contract.build @data[:contract]
181
183
  end
182
184
 
183
185
  # Check if given value was set by TWS to something vaguely "positive"
@@ -91,7 +91,7 @@ module IB
91
91
  [:dividends_to_expiry, :decimal]
92
92
 
93
93
  # This message is received when the market in an option or its underlier moves.
94
- # TWS�s option model volatilities, prices, and deltas, along with the present
94
+ # TWS option model volatilities, prices, and deltas, along with the present
95
95
  # value of dividends expected on that options underlier are received.
96
96
  # TickOption message contains following @data:
97
97
  # :ticker_id - Id that was specified previously in the call to reqMktData()
@@ -149,8 +149,8 @@ module IB
149
149
  [:why_held, :string] do
150
150
  "<OrderStatus: #{status} filled: #{filled}/#{remaining + filled}" +
151
151
  " @ last/avg: #{last_fill_price}/#{average_fill_price}" +
152
- (parent_id > 0 ? "parent_id: #{parent_id}" : "") +
153
- (why_held != "" ? "why_held: #{why_held}" : "") +
152
+ (parent_id > 0 ? " parent_id: #{parent_id}" : "") +
153
+ (why_held != "" ? " why_held: #{why_held}" : "") +
154
154
  " id/perm: #{order_id}/#{perm_id}>"
155
155
  end
156
156
 
@@ -302,7 +302,7 @@ module IB
302
302
 
303
303
  def load
304
304
  super
305
- @contract = Models::Contract.build @data[:contract]
305
+ @contract = IB::Contract.build @data[:contract]
306
306
  end
307
307
 
308
308
  def to_human
@@ -346,7 +346,7 @@ module IB
346
346
  class ContractData
347
347
  def load
348
348
  super
349
- @contract = Models::Contract.build @data[:contract]
349
+ @contract = IB::Contract.build @data[:contract]
350
350
  end
351
351
  end # ContractData
352
352
 
@@ -386,8 +386,8 @@ module IB
386
386
  load_map [proc { | | @server[:client_version] >= 53 },
387
387
  [:execution, :order_ref, :string]
388
388
  ]
389
- @contract = Models::Contract.build @data[:contract]
390
- @execution = Models::Execution.new @data[:execution]
389
+ @contract = IB::Contract.build @data[:contract]
390
+ @execution = IB::Execution.new @data[:execution]
391
391
  end
392
392
 
393
393
  def to_human
@@ -429,7 +429,7 @@ module IB
429
429
  class BondContractData
430
430
  def load
431
431
  super
432
- @contract = Models::Contract.build @data[:contract]
432
+ @contract = IB::Contract.build @data[:contract]
433
433
  end
434
434
  end # BondContractData
435
435
 
@@ -443,7 +443,7 @@ module IB
443
443
  class DeltaNeutralValidation
444
444
  def load
445
445
  super
446
- @contract = Models::Contract.build @data[:contract].merge(:under_comp => true)
446
+ @contract = IB::Contract.build @data[:contract].merge(:under_comp => true)
447
447
  end
448
448
  end # DeltaNeutralValidation
449
449
 
@@ -465,7 +465,7 @@ module IB
465
465
  class RealTimeBar
466
466
  def load
467
467
  super
468
- @bar = Models::Bar.new @data[:bar]
468
+ @bar = IB::Bar.new @data[:bar]
469
469
  end
470
470
 
471
471
  def to_human
@@ -549,15 +549,15 @@ module IB
549
549
  super
550
550
 
551
551
  @results = Array.new(@data[:count]) do |_|
552
- Models::Bar.new :time => socket.read_string,
553
- :open => socket.read_decimal,
554
- :high => socket.read_decimal,
555
- :low => socket.read_decimal,
556
- :close => socket.read_decimal,
557
- :volume => socket.read_int,
558
- :wap => socket.read_decimal,
559
- :has_gaps => socket.read_string,
560
- :trades => socket.read_int
552
+ IB::Bar.new :time => socket.read_string,
553
+ :open => socket.read_decimal,
554
+ :high => socket.read_decimal,
555
+ :low => socket.read_decimal,
556
+ :close => socket.read_decimal,
557
+ :volume => socket.read_int,
558
+ :wap => socket.read_decimal,
559
+ :has_gaps => socket.read_string,
560
+ :trades => socket.read_int
561
561
  end
562
562
  end
563
563