ib-ruby 0.4.3 → 0.4.20
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +32 -0
- data/HISTORY +68 -0
- data/README.rdoc +9 -6
- data/VERSION +1 -1
- data/bin/account_info +29 -0
- data/bin/contract_details +37 -0
- data/bin/depth_of_market +43 -0
- data/bin/historic_data +62 -0
- data/bin/{RequestHistoricData → historic_data_cli} +46 -91
- data/bin/market_data +49 -0
- data/bin/option_data +45 -0
- data/bin/template +21 -0
- data/bin/time_and_sales +63 -0
- data/lib/ib-ruby/connection.rb +166 -0
- data/lib/ib-ruby/constants.rb +91 -0
- data/lib/ib-ruby/messages/incoming.rb +807 -0
- data/lib/ib-ruby/messages/outgoing.rb +573 -0
- data/lib/ib-ruby/messages.rb +8 -1445
- data/lib/ib-ruby/models/bar.rb +26 -0
- data/lib/ib-ruby/models/contract.rb +335 -0
- data/lib/ib-ruby/models/execution.rb +55 -0
- data/lib/ib-ruby/models/model.rb +20 -0
- data/lib/ib-ruby/models/order.rb +262 -0
- data/lib/ib-ruby/models.rb +11 -0
- data/lib/ib-ruby/socket.rb +50 -0
- data/lib/ib-ruby/symbols/forex.rb +32 -72
- data/lib/ib-ruby/symbols/futures.rb +47 -68
- data/lib/ib-ruby/symbols/options.rb +30 -0
- data/lib/ib-ruby/symbols/stocks.rb +23 -0
- data/lib/ib-ruby/symbols.rb +9 -0
- data/lib/ib-ruby.rb +7 -8
- data/lib/legacy/bin/account_info_old +36 -0
- data/lib/legacy/bin/historic_data_old +81 -0
- data/lib/legacy/bin/market_data_old +68 -0
- data/lib/legacy/datatypes.rb +485 -0
- data/lib/legacy/ib-ruby.rb +10 -0
- data/lib/legacy/ib.rb +226 -0
- data/lib/legacy/messages.rb +1458 -0
- data/lib/version.rb +2 -3
- data/spec/ib-ruby/models/contract_spec.rb +261 -0
- data/spec/ib-ruby/models/order_spec.rb +64 -0
- data/spec/ib-ruby_spec.rb +0 -131
- metadata +106 -76
- data/bin/AccountInfo +0 -67
- data/bin/HistoricToCSV +0 -111
- data/bin/RequestMarketData +0 -78
- data/bin/SimpleTimeAndSales +0 -98
- data/bin/ib-ruby +0 -8
- data/lib/ib-ruby/datatypes.rb +0 -400
- data/lib/ib-ruby/ib.rb +0 -242
data/.gitignore
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
## MAC OS
|
2
|
+
.DS_Store
|
3
|
+
|
4
|
+
## TEXTMATE
|
5
|
+
*.tmproj
|
6
|
+
tmtags
|
7
|
+
|
8
|
+
## EMACS
|
9
|
+
*~
|
10
|
+
\#*
|
11
|
+
.\#*
|
12
|
+
|
13
|
+
## VIM
|
14
|
+
*.swp
|
15
|
+
|
16
|
+
## Idea
|
17
|
+
.idea
|
18
|
+
.bundle
|
19
|
+
.rakeTasks
|
20
|
+
*.iml
|
21
|
+
|
22
|
+
## PROJECT::GENERAL
|
23
|
+
coverage
|
24
|
+
config
|
25
|
+
data
|
26
|
+
rdoc
|
27
|
+
pkg
|
28
|
+
log
|
29
|
+
tmp
|
30
|
+
|
31
|
+
## PROJECT::SPECIFIC
|
32
|
+
*.db
|
data/HISTORY
CHANGED
@@ -21,3 +21,71 @@
|
|
21
21
|
== 0.4.3 / 2011-09-05
|
22
22
|
|
23
23
|
* Old tests converted into specs
|
24
|
+
|
25
|
+
== 0.4.4 / 2011-09-05
|
26
|
+
|
27
|
+
* IB references and Java examples added
|
28
|
+
|
29
|
+
== 0.4.5 / 2011-09-06
|
30
|
+
|
31
|
+
* Sample scripts updated
|
32
|
+
|
33
|
+
== 0.4.6 / 2011-09-07
|
34
|
+
|
35
|
+
* CSV Downloader Java examples added
|
36
|
+
|
37
|
+
== 0.4.7 / 2011-09-12
|
38
|
+
|
39
|
+
* Datatypes turned into Models
|
40
|
+
|
41
|
+
== 0.4.8 / 2011-09-12
|
42
|
+
|
43
|
+
* IB::Messages::Outgoing code compacted using macros
|
44
|
+
|
45
|
+
== 0.4.9 / 2011-09-15
|
46
|
+
|
47
|
+
* IB::Messages::Incoming rewritten
|
48
|
+
|
49
|
+
== 0.4.10 / 2011-09-16
|
50
|
+
|
51
|
+
* Market data request now working
|
52
|
+
|
53
|
+
== 0.4.11 / 2011-09-17
|
54
|
+
|
55
|
+
* New scripts working
|
56
|
+
|
57
|
+
== 0.4.12 / 2011-09-18
|
58
|
+
|
59
|
+
* historic_data script now functional
|
60
|
+
|
61
|
+
== 0.4.13 / 2011-09-18
|
62
|
+
|
63
|
+
* time_and_sales script now working
|
64
|
+
|
65
|
+
== 0.4.14 / 2011-09-18
|
66
|
+
|
67
|
+
* DOM script added
|
68
|
+
|
69
|
+
== 0.4.15 / 2011-09-18
|
70
|
+
|
71
|
+
* Messages like RTBars etc implemented
|
72
|
+
|
73
|
+
== 0.4.16 / 2011-09-19
|
74
|
+
|
75
|
+
* Execution Model added
|
76
|
+
|
77
|
+
== 0.4.17 / 2011-09-19
|
78
|
+
|
79
|
+
* option_data script now working
|
80
|
+
|
81
|
+
== 0.4.18 / 2011-09-19
|
82
|
+
|
83
|
+
* IB::Connection#subscribe syntax changed
|
84
|
+
|
85
|
+
== 0.4.19 / 2011-09-19
|
86
|
+
|
87
|
+
* All IB messages implemented
|
88
|
+
|
89
|
+
== 0.4.20 / 2011-09-19
|
90
|
+
|
91
|
+
* IB::Connection#subscribe now accepts Symbols with message names
|
data/README.rdoc
CHANGED
@@ -1,16 +1,16 @@
|
|
1
|
-
=
|
1
|
+
= ib-ruby
|
2
2
|
by:: Arvicco
|
3
3
|
url:: http://github.com/arvicco/ib-ruby
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
This is a fork of http://github.com/wdevauld/ib-ruby by Wes Devauld,
|
6
|
+
that is in turn forked from http://github.com/pjlegato/ib-ruby by Paul Legato.
|
7
7
|
|
8
8
|
== DESCRIPTION:
|
9
9
|
|
10
10
|
Ruby Implementation of the Interactive Broker' TWS API
|
11
11
|
|
12
12
|
The goal of this fork is to modernize library structure (Bundler/Gemfile/etc) and
|
13
|
-
then roll out a new version based on latest IB TWS API.
|
13
|
+
then roll out a new version based on latest IB TWS API v.965.
|
14
14
|
|
15
15
|
== FEATURES/PROBLEMS:
|
16
16
|
|
@@ -39,8 +39,11 @@ connections on localhost.
|
|
39
39
|
First, start up Interactive Broker's Trader Work Station.
|
40
40
|
Ensure it is configured to allow API connections on localhost.
|
41
41
|
|
42
|
-
>> require 'ib-ruby'
|
43
|
-
>>
|
42
|
+
>> require 'ib-ruby'
|
43
|
+
>> ib = IB::Connection.new
|
44
|
+
>> ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
|
45
|
+
>> ib.subscribe(IB::Messages::Incoming::AccountValue) { |msg| puts msg.to_human }
|
46
|
+
>> ib.send IB::Messages::Outgoing::RequestAccountData.new :subscribe => true
|
44
47
|
|
45
48
|
== LICENSE:
|
46
49
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.20
|
data/bin/account_info
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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)
|
9
|
+
|
10
|
+
require 'rubygems'
|
11
|
+
require 'bundler/setup'
|
12
|
+
require 'ib-ruby'
|
13
|
+
|
14
|
+
# First, connect to IB TWS.
|
15
|
+
ib = IB::Connection.new
|
16
|
+
|
17
|
+
# Subscribe to TWS alerts/errors and account-related messages
|
18
|
+
# that TWS sends in response to account data request
|
19
|
+
ib.subscribe(:Alert, :AccountValue,
|
20
|
+
:PortfolioValue, :AccountUpdateTime) { |msg| puts msg.to_human }
|
21
|
+
|
22
|
+
ib.send :RequestAccountData, :subscribe => true
|
23
|
+
|
24
|
+
puts "\nSubscribing to IB account data"
|
25
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
26
|
+
gets
|
27
|
+
puts "Cancelling account data subscription.."
|
28
|
+
|
29
|
+
ib.send :RequestAccountData, :subscribe => false
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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)
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bundler/setup'
|
11
|
+
require 'ib-ruby'
|
12
|
+
|
13
|
+
# Definition of what we want market data for. We have to keep track of what ticker id
|
14
|
+
# corresponds to what symbol ourselves, because the ticks don't include any other
|
15
|
+
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
|
16
|
+
@market = {123 => IB::Symbols::Stocks[:wfc],
|
17
|
+
125 => IB::Symbols::Options[:wfc20],
|
18
|
+
129 => IB::Symbols::Stocks[:wrong]}
|
19
|
+
|
20
|
+
# Connect to IB TWS.
|
21
|
+
ib = IB::Connection.new
|
22
|
+
|
23
|
+
# Subscribe to TWS alerts/errors
|
24
|
+
ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
|
25
|
+
|
26
|
+
# Now, subscribe to ContractData incoming events. The code passed in the block
|
27
|
+
# will be executed when a message of that type is received, with the received
|
28
|
+
# message as its argument. In this case, we just print out the data.
|
29
|
+
ib.subscribe(:ContractData) { |msg| puts msg.contract.inspect }
|
30
|
+
|
31
|
+
# Now we actually request historical data for the symbols we're interested in. TWS will
|
32
|
+
# respond with a HistoricalData message, which will be processed by the code above.
|
33
|
+
@market.each_pair do |id, contract|
|
34
|
+
ib.send :RequestContractData, :id => id, :contract => contract
|
35
|
+
end
|
36
|
+
|
37
|
+
sleep 3 # Wait for IB to respond to our request
|
data/bin/depth_of_market
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This script connects to IB API and subscribes to L2 (depth of market) data for
|
4
|
+
# specific symbols
|
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
|
+
require 'rubygems'
|
11
|
+
require 'bundler/setup'
|
12
|
+
require 'ib-ruby'
|
13
|
+
|
14
|
+
# Definition of what we want L2 data for. We have to keep track of what ticker id
|
15
|
+
# corresponds to what symbol ourselves, because the ticks don't include any other
|
16
|
+
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
|
17
|
+
@market = {123 => IB::Symbols::Stocks[:wfc],
|
18
|
+
456 => IB::Symbols::Futures[:ym],
|
19
|
+
789 => IB::Symbols::Forex[:gbpusd]
|
20
|
+
}
|
21
|
+
|
22
|
+
# First, connect to IB TWS.
|
23
|
+
ib = IB::Connection.new
|
24
|
+
|
25
|
+
# Subscribe to TWS alerts/errors
|
26
|
+
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
27
|
+
|
28
|
+
# Subscribe to MarketDepth events.
|
29
|
+
ib.subscribe(:MarketDepth) do |msg|
|
30
|
+
puts @market[msg.data[:id]].description + ": " + msg.to_human
|
31
|
+
end
|
32
|
+
|
33
|
+
# Now we actually request market data for the symbols we're interested in.
|
34
|
+
@market.each_pair do |id, contract|
|
35
|
+
ib.send :RequestMarketDepth, :id => id, :contract => contract, :num_rows => 5
|
36
|
+
end
|
37
|
+
|
38
|
+
puts "\nSubscribed to market data"
|
39
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
40
|
+
gets
|
41
|
+
puts "Cancelling market data subscription.."
|
42
|
+
|
43
|
+
@market.each_pair { |id, contract| ib.send :CancelMarketDepth, :id => id }
|
data/bin/historic_data
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This script downloads historic data for specific symbols 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)
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bundler/setup'
|
11
|
+
require 'ib-ruby'
|
12
|
+
|
13
|
+
### Configurable Options
|
14
|
+
Quiet = false # if Quiet == false, status data will be printed to STDERR
|
15
|
+
Timeout = 10 # How long to wait for messages from TWS before exiting, sec
|
16
|
+
|
17
|
+
# Definition of what we want data for. We have to keep track of what ticker id
|
18
|
+
# corresponds to what symbol ourselves, because the ticks don't include any other
|
19
|
+
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
|
20
|
+
@market = {123 => IB::Symbols::Stocks[:wfc],
|
21
|
+
456 => IB::Symbols::Futures[:ym],
|
22
|
+
789 => IB::Symbols::Forex[:gbpusd] # No historical market data for GBP/CASH@IDEALPRO Last 60
|
23
|
+
}
|
24
|
+
|
25
|
+
# Connect to IB TWS.
|
26
|
+
ib = IB::Connection.new
|
27
|
+
|
28
|
+
# Subscribe to TWS alerts/errors
|
29
|
+
ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
|
30
|
+
|
31
|
+
# Now, subscribe to HistoricalData incoming events. The code passed in the block
|
32
|
+
# will be executed when a message of that type is received, with the received
|
33
|
+
# message as its argument. In this case, we just print out the data.
|
34
|
+
#
|
35
|
+
# Note that we have to look the ticker id of each incoming message
|
36
|
+
# up in local memory to figure out what it's for.
|
37
|
+
ib.subscribe(IB::Messages::Incoming::HistoricalData) do |msg|
|
38
|
+
STDERR.puts @market[msg.data[:id]].description + ": " + msg.data[:count].to_s + " items:" unless Quiet
|
39
|
+
|
40
|
+
msg.data[:results].each do |datum|
|
41
|
+
@last_msg_time = Time.now.to_i
|
42
|
+
|
43
|
+
STDERR.puts " " + datum.to_s unless Quiet
|
44
|
+
#STDOUT.puts "#{datum.date},#{datum.open},#{datum.high},#{datum.low},#{datum.close},#{datum.volume}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Now we actually request historical data for the symbols we're interested in. TWS will
|
49
|
+
# respond with a HistoricalData message, which will be processed by the code above.
|
50
|
+
@market.each_pair do |id, contract|
|
51
|
+
ib.send IB::Messages::Outgoing::RequestHistoricalData.new(
|
52
|
+
:id => id,
|
53
|
+
:contract => contract,
|
54
|
+
:end_date_time => Time.now.to_ib,
|
55
|
+
:duration => '2 D', # ?
|
56
|
+
:bar_size => '1 min', #IB::OutgoingMessages::BAR_SIZES.key(:hour),
|
57
|
+
:what_to_show => :trades,
|
58
|
+
:use_rth => 1,
|
59
|
+
:format_date => 1)
|
60
|
+
end
|
61
|
+
|
62
|
+
sleep 5 # Wait for IB to respond to our request
|
@@ -1,77 +1,39 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
#
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or modify
|
6
|
-
# it under the terms of the GNU Lesser General Public License as
|
7
|
-
# published by the Free Software Foundation; either version 2.1 of the
|
8
|
-
# License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful, but
|
11
|
-
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
18
|
-
# 02110-1301 USA
|
19
|
-
#
|
20
|
-
|
21
|
-
require File.expand_path(
|
22
|
-
File.join(File.dirname(__FILE__), '..', 'lib', 'ib-ruby'))
|
3
|
+
# This script connects to IB API, and downloads historic data
|
4
|
+
# TODO: Fix the Historical command line client
|
23
5
|
|
24
6
|
require 'rubygems'
|
25
7
|
require 'time'
|
26
8
|
require 'duration'
|
9
|
+
require 'pathname'
|
27
10
|
require 'getopt/long'
|
11
|
+
require 'bundler/setup'
|
12
|
+
|
13
|
+
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
|
14
|
+
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
15
|
+
|
16
|
+
require 'ib-ruby'
|
28
17
|
|
29
18
|
include Getopt
|
30
19
|
|
31
20
|
opt = Getopt::Long.getopts(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
21
|
+
["--help", BOOLEAN],
|
22
|
+
["--end", REQUIRED],
|
23
|
+
["--security", REQUIRED],
|
24
|
+
["--duration", REQUIRED],
|
25
|
+
["--barsize", REQUIRED],
|
26
|
+
["--header", BOOLEAN],
|
27
|
+
["--dateformat", REQUIRED],
|
28
|
+
["--nonregularhours", BOOLEAN],
|
29
|
+
["--verbose", BOOLEAN],
|
30
|
+
["--veryverbose", BOOLEAN]
|
42
31
|
)
|
43
32
|
|
44
33
|
if opt["help"] || opt["security"].nil? || opt["security"].empty?
|
45
34
|
puts <<ENDHELP
|
46
35
|
|
47
|
-
|
48
|
-
|
49
|
-
This library is free software; you can redistribute it and/or modify
|
50
|
-
it under the terms of the GNU Lesser General Public License as
|
51
|
-
published by the Free Software Foundation; either version 2.1 of the
|
52
|
-
License, or (at your option) any later version.
|
53
|
-
|
54
|
-
This library is distributed in the hope that it will be useful, but
|
55
|
-
WITHOUT ANY WARRANTY; without even the implied warranty of
|
56
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
57
|
-
Lesser General Public License for more details.
|
58
|
-
|
59
|
-
You should have received a copy of the GNU Lesser General Public
|
60
|
-
License along with this library; if not, write to the Free Software
|
61
|
-
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
62
|
-
02110-1301 USA
|
63
|
-
|
64
|
-
The author and this software are not connected with Interactive
|
65
|
-
Brokers in any way, nor do they endorse us.
|
66
|
-
|
67
|
-
************************************************************************************
|
68
|
-
|
69
|
-
>> YOUR USE OF THIS PROGRAM IS ENTIRELY AT YOUR OWN RISK. <<
|
70
|
-
>> IT MAY CONTAIN POTENTIALLY COSTLY BUGS, ERRORS, ETC., BOTH KNOWN AND UNKNOWN. <<
|
71
|
-
>> DO NOT USE THIS SOFTWARE IF YOU ARE UNWILLING TO ACCEPT ALL RISK IN DOING SO. <<
|
72
|
-
|
73
|
-
************************************************************************************
|
74
|
-
|
36
|
+
***
|
75
37
|
|
76
38
|
This program requires a TWS running on localhost on the standard port
|
77
39
|
that uses API protocol version 15 or higher. Any modern TWS should
|
@@ -153,7 +115,7 @@ Possible values (from the IB documentation):
|
|
153
115
|
data in CSV format.
|
154
116
|
|
155
117
|
ENDHELP
|
156
|
-
|
118
|
+
|
157
119
|
exit
|
158
120
|
|
159
121
|
end
|
@@ -169,11 +131,9 @@ if DURATION > 86400
|
|
169
131
|
exit(1)
|
170
132
|
end
|
171
133
|
|
172
|
-
|
173
134
|
# This is the last time we want data for.
|
174
135
|
END_DATE_TIME = (opt["end"] && eval(opt["end"]).to_ib) || Time.now.to_ib
|
175
136
|
|
176
|
-
|
177
137
|
# This can be :trades, :midpoint, :bid, or :asked
|
178
138
|
WHAT = (opt["what"] && opt["what"].to_sym) || :trades
|
179
139
|
|
@@ -223,16 +183,11 @@ VERBOSE = !opt["verbose"].nil?
|
|
223
183
|
#
|
224
184
|
# Note that as of 4/07 there is no historical data available for forex spot.
|
225
185
|
#
|
226
|
-
@market =
|
227
|
-
{
|
228
|
-
123 => opt["security"]
|
229
|
-
}
|
230
|
-
|
186
|
+
@market = {123 => opt["security"]}
|
231
187
|
|
232
188
|
# First, connect to IB TWS.
|
233
189
|
ib = IB::IB.new
|
234
190
|
|
235
|
-
|
236
191
|
# Default level is quiet, only warnings printed.
|
237
192
|
# IB::IBLogger.level = Logger::Severity::ERROR
|
238
193
|
|
@@ -256,35 +211,35 @@ lastMessageTime = Queue.new # for communicating with the reader thread.
|
|
256
211
|
# up in local memory to figure out what security it relates to.
|
257
212
|
# The incoming message packet from TWS just identifies it by ticker id.
|
258
213
|
#
|
259
|
-
ib.subscribe(IB::IncomingMessages::HistoricalData, lambda {|msg|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
214
|
+
ib.subscribe(IB::IncomingMessages::HistoricalData, lambda { |msg|
|
215
|
+
STDERR.puts @market[msg.data[:req_id]].description + ": " + msg.data[:item_count].to_s("F") + " items:" if VERBOSE
|
216
|
+
|
217
|
+
msg.data[:history].each { |datum|
|
218
|
+
puts(if VERBOSE
|
219
|
+
datum.to_s
|
220
|
+
else
|
221
|
+
"#{datum.date},#{datum.open.to_s("F")},#{datum.high.to_s("F")},#{datum.low.to_s("F")}," +
|
222
|
+
"#{datum.close.to_s("F")},#{datum.volume},#{datum.wap.to_s("F")},#{datum.has_gaps}"
|
223
|
+
end
|
224
|
+
)
|
225
|
+
}
|
226
|
+
lastMessageTime.push(Time.now)
|
227
|
+
})
|
273
228
|
|
274
229
|
# Now we actually request historical data for the symbols we're
|
275
230
|
# interested in. TWS will respond with a HistoricalData message,
|
276
231
|
# which will be received by the code above.
|
277
232
|
|
278
|
-
@market.each_pair {|id, contract|
|
233
|
+
@market.each_pair { |id, contract|
|
279
234
|
msg = IB::OutgoingMessages::RequestHistoricalData.new({
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
235
|
+
:ticker_id => id,
|
236
|
+
:contract => contract,
|
237
|
+
:end_date_time => END_DATE_TIME,
|
238
|
+
:duration => DURATION, # seconds == 1 hour
|
239
|
+
:bar_size => BAR_SIZE, # 1 minute bars
|
240
|
+
:what_to_show => WHAT,
|
241
|
+
:use_RTH => REGULAR_HOURS_ONLY,
|
242
|
+
:format_date => DATE_FORMAT
|
288
243
|
})
|
289
244
|
ib.dispatch(msg)
|
290
245
|
}
|
data/bin/market_data
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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)
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bundler/setup'
|
11
|
+
require 'ib-ruby'
|
12
|
+
|
13
|
+
# Definition of what we want market data for. We have to keep track of what ticker id
|
14
|
+
# corresponds to what symbol ourselves, because the ticks don't include any other
|
15
|
+
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
|
16
|
+
@market = {123 => IB::Symbols::Forex[:gbpusd],
|
17
|
+
456 => IB::Symbols::Forex[:eurusd],
|
18
|
+
789 => IB::Symbols::Forex[:usdcad]}
|
19
|
+
|
20
|
+
# First, connect to IB TWS.
|
21
|
+
ib = IB::Connection.new
|
22
|
+
|
23
|
+
## Subscribe to TWS alerts/errors
|
24
|
+
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
25
|
+
|
26
|
+
# Subscribe to TickerPrice and TickerSize events. The code passed in the block will
|
27
|
+
# be executed when a message of that type is received, with the received message as its
|
28
|
+
# argument. In this case, we just print out the tick.
|
29
|
+
#
|
30
|
+
# Note that we have to look the ticker id of each incoming message
|
31
|
+
# up in local memory to figure out what it's for.
|
32
|
+
#
|
33
|
+
# (N.B. The description field is not from IB TWS. It is defined
|
34
|
+
# locally in forex.rb, and is just arbitrary text.)
|
35
|
+
ib.subscribe(:TickPrice, :TickSize) do |msg|
|
36
|
+
puts @market[msg.data[:id]].description + ": " + msg.to_human
|
37
|
+
end
|
38
|
+
|
39
|
+
# Now we actually request market data for the symbols we're interested in.
|
40
|
+
@market.each_pair do |id, contract|
|
41
|
+
ib.send :RequestMarketData, :id => id, :contract => contract
|
42
|
+
end
|
43
|
+
|
44
|
+
puts "\nSubscribed to market data"
|
45
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
46
|
+
gets
|
47
|
+
puts "Cancelling market data subscription.."
|
48
|
+
|
49
|
+
@market.each_pair { |id, _| ib.send :CancelMarketData, :id => id }
|
data/bin/option_data
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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)
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bundler/setup'
|
11
|
+
require 'ib-ruby'
|
12
|
+
|
13
|
+
# Definition of what we want market data for. We have to keep track of what ticker id
|
14
|
+
# corresponds to what symbol ourselves, because the ticks don't include any other
|
15
|
+
# identifying information. The choice of ticker ids is, as far as I can tell, arbitrary.
|
16
|
+
@market = {123 => IB::Symbols::Options[:wfc20],
|
17
|
+
125 => IB::Symbols::Options[:z50]}
|
18
|
+
|
19
|
+
# First, connect to IB TWS.
|
20
|
+
ib = IB::Connection.new
|
21
|
+
|
22
|
+
## Subscribe to TWS alerts/errors
|
23
|
+
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
24
|
+
|
25
|
+
# Subscribe to Ticker... events. The code passed in the block will be executed when
|
26
|
+
# any message of that type is received, with the received message as its argument.
|
27
|
+
# In this case, we just print out the tick.
|
28
|
+
#
|
29
|
+
# (N.B. The description field is not from IB TWS. It is defined
|
30
|
+
# locally in forex.rb, and is just arbitrary text.)
|
31
|
+
ib.subscribe(:TickPrice, :TickSize, :TickOption) do |msg|
|
32
|
+
puts @market[msg.data[:id]].description + ": " + msg.to_human
|
33
|
+
end
|
34
|
+
|
35
|
+
# Now we actually request market data for the symbols we're interested in.
|
36
|
+
@market.each_pair do |id, contract|
|
37
|
+
ib.send :RequestMarketData, :id => id, :contract => contract
|
38
|
+
end
|
39
|
+
|
40
|
+
puts "\nSubscribed to market data"
|
41
|
+
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
42
|
+
gets
|
43
|
+
puts "Cancelling market data subscription.."
|
44
|
+
|
45
|
+
@market.each_pair { |id, contract| ib.send :CancelMarketData, :id => id }
|
data/bin/template
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Your script description here...
|
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
|
+
require 'rubygems'
|
10
|
+
require 'bundler/setup'
|
11
|
+
require 'ib-ruby'
|
12
|
+
|
13
|
+
# Connect to IB TWS.
|
14
|
+
ib = IB::Connection.new
|
15
|
+
|
16
|
+
# Subscribe to TWS alerts/errors
|
17
|
+
ib.subscribe(IB::Messages::Incoming::Alert) { |msg| puts msg.to_human }
|
18
|
+
|
19
|
+
# Put your code here
|
20
|
+
# ...
|
21
|
+
|