ib-ruby 0.7.3 → 0.7.4
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +4 -0
- data/README.md +60 -30
- data/TODO +1 -0
- data/VERSION +1 -1
- data/bin/account_info +1 -4
- data/bin/cancel_orders +0 -3
- data/bin/contract_details +2 -5
- data/bin/depth_of_market +1 -4
- data/bin/fa_accounts +22 -0
- data/bin/historic_data +1 -4
- data/bin/historic_data_cli +0 -4
- data/bin/list_orders +2 -6
- data/bin/market_data +1 -4
- data/bin/option_data +2 -5
- data/bin/place_combo_order +17 -22
- data/bin/place_order +6 -10
- data/bin/tick_data +6 -9
- data/bin/time_and_sales +2 -5
- data/lib/ib-ruby/connection.rb +10 -5
- data/lib/ib-ruby/messages/incoming/open_order.rb +15 -13
- data/lib/ib-ruby/messages/incoming/ticks.rb +1 -1
- data/lib/ib-ruby/messages/incoming.rb +18 -18
- data/lib/ib-ruby/messages/outgoing.rb +2 -2
- data/lib/ib-ruby/messages.rb +3 -7
- data/lib/ib-ruby/models/{contract → contracts}/bag.rb +5 -8
- data/lib/ib-ruby/models/contracts/contract.rb +296 -0
- data/lib/ib-ruby/models/{contract → contracts}/option.rb +2 -4
- data/lib/ib-ruby/models/contracts.rb +27 -0
- data/lib/ib-ruby/models/execution.rb +1 -1
- data/lib/ib-ruby/models/order.rb +6 -17
- data/lib/ib-ruby/models.rb +9 -7
- data/lib/ib-ruby/symbols/forex.rb +50 -50
- data/lib/ib-ruby/symbols/futures.rb +47 -47
- data/lib/ib-ruby/symbols/options.rb +23 -23
- data/lib/ib-ruby/symbols/stocks.rb +14 -14
- data/lib/ib-ruby.rb +17 -9
- data/spec/README.md +6 -0
- data/spec/account_helper.rb +1 -1
- data/spec/combo_helper.rb +31 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +4 -4
- data/spec/ib-ruby/models/contract_spec.rb +37 -26
- data/spec/ib-ruby/models/execution_spec.rb +5 -5
- data/spec/ib-ruby/models/order_spec.rb +16 -16
- data/spec/integration/contract_info_spec.rb +8 -10
- data/spec/integration/historic_data_spec.rb +1 -1
- data/spec/integration/market_data_spec.rb +5 -5
- data/spec/integration/orders/attached_spec.rb +87 -0
- data/spec/integration/orders/combo_spec.rb +52 -65
- data/spec/integration/orders/placement_spec.rb +8 -8
- data/spec/order_helper.rb +97 -28
- data/spec/spec_helper.rb +2 -2
- metadata +12 -5
- data/lib/ib-ruby/models/contract.rb +0 -308
data/HISTORY
CHANGED
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
|
-
##
|
16
|
+
## SUMMARY:
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
25
|
-
|
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
|
-
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
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::
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
78
|
-
|
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
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
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
data/bin/contract_details
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# This script gets details for specific
|
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
|
|
data/bin/historic_data_cli
CHANGED
@@ -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
|
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
|
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
|
|
data/bin/place_combo_order
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# This script
|
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::
|
21
|
-
|
22
|
-
|
23
|
-
|
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::
|
27
|
+
IB::ComboLeg.new :con_id => con_id, :weight => weight
|
32
28
|
end
|
33
29
|
|
34
30
|
# Create new Combo contract
|
35
|
-
IB::
|
36
|
-
|
37
|
-
|
38
|
-
|
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::
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
58
|
+
gets
|
data/bin/place_order
CHANGED
@@ -1,13 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
# This script
|
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::
|
22
|
-
|
23
|
-
|
24
|
-
|
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::
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
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
|
|
data/lib/ib-ruby/connection.rb
CHANGED
@@ -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, :
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
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
|
-
|
171
|
-
|
172
|
-
[:order, :
|
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 =
|
180
|
-
@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
|
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 =
|
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 =
|
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 =
|
390
|
-
@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 =
|
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 =
|
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 =
|
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
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
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
|
|