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.
- 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
|
|