ib-ruby 0.7.4 → 0.7.6
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/.gitignore +3 -0
- data/HISTORY +8 -0
- data/README.md +2 -2
- data/Rakefile +15 -0
- data/TODO +7 -2
- data/VERSION +1 -1
- data/bin/account_info +1 -1
- data/bin/cancel_orders +1 -1
- data/bin/contract_details +1 -1
- data/bin/depth_of_market +1 -1
- data/bin/fa_accounts +1 -1
- data/bin/fundamental_data +42 -0
- data/bin/historic_data +1 -1
- data/bin/historic_data_cli +1 -1
- data/bin/list_orders +1 -2
- data/bin/market_data +1 -1
- data/bin/option_data +1 -1
- data/bin/place_combo_order +1 -1
- data/bin/place_order +1 -1
- data/bin/template +1 -4
- data/bin/tick_data +2 -2
- data/bin/time_and_sales +1 -1
- data/lib/ib-ruby.rb +4 -0
- data/lib/ib-ruby/connection.rb +50 -34
- data/lib/ib-ruby/constants.rb +232 -37
- data/lib/ib-ruby/db.rb +25 -0
- data/lib/ib-ruby/extensions.rb +51 -1
- data/lib/ib-ruby/messages/abstract_message.rb +0 -8
- data/lib/ib-ruby/messages/incoming.rb +18 -493
- data/lib/ib-ruby/messages/incoming/abstract_message.rb +100 -0
- data/lib/ib-ruby/messages/incoming/alert.rb +34 -0
- data/lib/ib-ruby/messages/incoming/contract_data.rb +82 -0
- data/lib/ib-ruby/messages/incoming/delta_neutral_validation.rb +20 -0
- data/lib/ib-ruby/messages/incoming/execution_data.rb +59 -0
- data/lib/ib-ruby/messages/incoming/historical_data.rb +55 -0
- data/lib/ib-ruby/messages/incoming/market_depths.rb +44 -0
- data/lib/ib-ruby/messages/incoming/open_order.rb +32 -16
- data/lib/ib-ruby/messages/incoming/order_status.rb +67 -0
- data/lib/ib-ruby/messages/incoming/portfolio_value.rb +39 -0
- data/lib/ib-ruby/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib-ruby/messages/incoming/scanner_data.rb +49 -0
- data/lib/ib-ruby/messages/outgoing.rb +25 -223
- data/lib/ib-ruby/messages/outgoing/abstract_message.rb +61 -0
- data/lib/ib-ruby/messages/outgoing/bar_requests.rb +149 -0
- data/lib/ib-ruby/messages/outgoing/place_order.rb +24 -0
- data/lib/ib-ruby/models.rb +4 -0
- data/lib/ib-ruby/models/bar.rb +31 -14
- data/lib/ib-ruby/models/combo_leg.rb +48 -23
- data/lib/ib-ruby/models/contracts.rb +2 -2
- data/lib/ib-ruby/models/contracts/bag.rb +11 -7
- data/lib/ib-ruby/models/contracts/contract.rb +90 -66
- data/lib/ib-ruby/models/contracts/option.rb +16 -7
- data/lib/ib-ruby/models/execution.rb +34 -18
- data/lib/ib-ruby/models/model.rb +15 -7
- data/lib/ib-ruby/models/model_properties.rb +101 -44
- data/lib/ib-ruby/models/order.rb +176 -187
- data/lib/ib-ruby/models/order_state.rb +99 -0
- data/lib/ib-ruby/symbols/forex.rb +10 -10
- data/lib/ib-ruby/symbols/futures.rb +6 -6
- data/lib/ib-ruby/symbols/stocks.rb +3 -3
- data/spec/account_helper.rb +4 -5
- data/spec/combo_helper.rb +4 -4
- data/spec/db.rb +18 -0
- data/spec/ib-ruby/messages/{incoming_spec.rb → incoming/alert_spec.rb} +1 -0
- data/spec/ib-ruby/messages/incoming/open_order_spec.rb +100 -0
- data/spec/ib-ruby/messages/incoming/order_status_spec.rb +74 -0
- data/spec/ib-ruby/messages/{outgoing_spec.rb → outgoing/account_data_spec.rb} +0 -0
- data/spec/ib-ruby/messages/outgoing/market_data_type_spec.rb +44 -0
- data/spec/ib-ruby/models/bag_spec.rb +97 -0
- data/spec/ib-ruby/models/bar_spec.rb +45 -0
- data/spec/ib-ruby/models/combo_leg_spec.rb +56 -40
- data/spec/ib-ruby/models/contract_spec.rb +134 -170
- data/spec/ib-ruby/models/execution_spec.rb +35 -50
- data/spec/ib-ruby/models/option_spec.rb +127 -0
- data/spec/ib-ruby/models/order_spec.rb +89 -68
- data/spec/ib-ruby/models/order_state_spec.rb +55 -0
- data/spec/integration/contract_info_spec.rb +4 -6
- data/spec/integration/fundamental_data_spec.rb +41 -0
- data/spec/integration/historic_data_spec.rb +4 -4
- data/spec/integration/market_data_spec.rb +1 -3
- data/spec/integration/orders/attached_spec.rb +8 -10
- data/spec/integration/orders/combo_spec.rb +2 -2
- data/spec/integration/orders/execution_spec.rb +0 -1
- data/spec/integration/orders/placement_spec.rb +1 -3
- data/spec/integration/orders/valid_ids_spec.rb +1 -2
- data/spec/message_helper.rb +1 -1
- data/spec/model_helper.rb +211 -0
- data/spec/order_helper.rb +44 -37
- data/spec/spec_helper.rb +36 -23
- data/spec/v.rb +7 -0
- data/tasks/doc.rake +1 -1
- metadata +116 -12
- data/spec/integration/orders/open_order +0 -98
data/.gitignore
CHANGED
data/HISTORY
CHANGED
data/README.md
CHANGED
@@ -93,9 +93,9 @@ lines of code - and without sacrificing code readability or flexibility.
|
|
93
93
|
ib.subscribe(:OpenOrder) { |msg| puts "Placed: #{msg.order}!" }
|
94
94
|
ib.subscribe(:ExecutionData) { |msg| puts "Filled: #{msg.execution}!" }
|
95
95
|
contract = IB::Contract.new :symbol => 'WFC', :exchange => 'NYSE',
|
96
|
-
:currency => 'USD', :sec_type =>
|
96
|
+
:currency => 'USD', :sec_type => :stock
|
97
97
|
buy_order = IB::Order.new :total_quantity => 100, :limit_price => 21.00,
|
98
|
-
:action =>
|
98
|
+
:action => :buy, :order_type => :limit
|
99
99
|
ib.place_order buy_order, contract
|
100
100
|
ib.wait_for :ExecutionData
|
101
101
|
|
data/Rakefile
CHANGED
@@ -23,3 +23,18 @@ CLASS_NAME = IB
|
|
23
23
|
Dir['tasks/*.rake'].sort.each { |file| load file }
|
24
24
|
|
25
25
|
# Project-specific tasks
|
26
|
+
|
27
|
+
## Migrations
|
28
|
+
|
29
|
+
# rake db:new_migration name=FooBarMigration
|
30
|
+
# rake db:migrate
|
31
|
+
# rake db:migrate VERSION=20081220234130
|
32
|
+
# rake db:migrate:up VERSION=20081220234130
|
33
|
+
# rake db:migrate DB=osx-test
|
34
|
+
# rake db:rollback
|
35
|
+
# rake db:rollback STEP=3
|
36
|
+
begin
|
37
|
+
require 'tasks/standalone_migrations'
|
38
|
+
rescue LoadError => e
|
39
|
+
puts "gem install standalone_migrations to get db:migrate:* tasks! (Error: #{e})"
|
40
|
+
end
|
data/TODO
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
Plan:
|
2
2
|
|
3
|
-
|
3
|
+
0. Extract OrderState/UnderComp objects, for better record keeping
|
4
|
+
|
5
|
+
1. Add ActiveRecord backend to all Models
|
4
6
|
|
5
7
|
2. Make ActiveModel-like attributes Hash for easy attributes updating
|
6
8
|
|
@@ -14,10 +16,11 @@ http://finance.groups.yahoo.com/group/TWSAPI/message/25413
|
|
14
16
|
|
15
17
|
6. @received_at timestamp in messages
|
16
18
|
|
17
|
-
7.
|
19
|
+
7. Detailed message documentation
|
18
20
|
|
19
21
|
8. Move Float values to Decimal (roundoff errors showed in spec!)
|
20
22
|
|
23
|
+
|
21
24
|
Done:
|
22
25
|
|
23
26
|
1. Create integration tests for basic use cases
|
@@ -38,3 +41,5 @@ Ideas for future:
|
|
38
41
|
|
39
42
|
2. Tweak IB::Message API for speed (use class methods)
|
40
43
|
|
44
|
+
3. Create integration tests for more use cases (spec/README)
|
45
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.6
|
data/bin/account_info
CHANGED
data/bin/cancel_orders
CHANGED
@@ -5,8 +5,8 @@
|
|
5
5
|
# robot goes crazy and opens gazillions of wrong limit orders.
|
6
6
|
|
7
7
|
require 'rubygems'
|
8
|
-
require 'pathname'
|
9
8
|
require 'bundler/setup'
|
9
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
10
10
|
require 'ib-ruby'
|
11
11
|
|
12
12
|
# First, connect to IB TWS.
|
data/bin/contract_details
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script gets details for specific contract from IB
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# Definition of what we want market data for. We have to keep track of what ticker id
|
data/bin/depth_of_market
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# specific symbols
|
5
5
|
|
6
6
|
require 'rubygems'
|
7
|
-
require 'pathname'
|
8
7
|
require 'bundler/setup'
|
8
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
9
9
|
require 'ib-ruby'
|
10
10
|
|
11
11
|
# Definition of what we want L2 data for. We have to keep track of what ticker id
|
data/bin/fa_accounts
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script receives Financial Adviser and Managed Accounts info
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# First, connect to IB TWS.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This script downloads Fundamental data for specific symbols from IB
|
4
|
+
# This only works IF you have Reuters data subscription!
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'bundler/setup'
|
8
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
9
|
+
|
10
|
+
require 'ib-ruby'
|
11
|
+
require 'xmlsimple'
|
12
|
+
require 'pp'
|
13
|
+
|
14
|
+
|
15
|
+
ib = IB::Connection.new :client_id => 1112 #, :port => 7496 # TWS
|
16
|
+
|
17
|
+
ib.subscribe(:Alert) { |msg| puts msg.to_human }
|
18
|
+
|
19
|
+
# Fundamental Data will arrive as XML. Need to parse it
|
20
|
+
ib.subscribe(:FundamentalData) do |msg|
|
21
|
+
puts 'Got fundamental data.'
|
22
|
+
@xml = XmlSimple.xml_in(msg.data)
|
23
|
+
pp @xml
|
24
|
+
@parsing_finished = true
|
25
|
+
end
|
26
|
+
|
27
|
+
ibm = IB::Contract.new :symbol => 'IBM',
|
28
|
+
:exchange => 'NYSE',
|
29
|
+
:currency => 'USD',
|
30
|
+
:sec_type => 'STK'
|
31
|
+
|
32
|
+
# Request Fundamental Data for IBM. Possible report types:
|
33
|
+
# 'estimates' - Estimates
|
34
|
+
# 'finstat' - Financial statements
|
35
|
+
# 'snapshot' - Summary
|
36
|
+
ib.send_message :RequestFundamentalData,
|
37
|
+
:id => 10,
|
38
|
+
:contract => ibm,
|
39
|
+
:report_type => 'snapshot'
|
40
|
+
|
41
|
+
# Needs some time to receive, parse and print XML. Standard timeout of 1 sec is too low.
|
42
|
+
ib.wait_for(40) { @parsing_finished }
|
data/bin/historic_data
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script downloads historic data for specific symbols from IB
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# Definition of what we want data for. We have to keep track of what ticker id
|
data/bin/historic_data_cli
CHANGED
data/bin/list_orders
CHANGED
@@ -2,10 +2,9 @@
|
|
2
2
|
#
|
3
3
|
# This script retrieves list of all Orders from TWS
|
4
4
|
|
5
|
-
require 'pathname'
|
6
5
|
require 'rubygems'
|
7
6
|
require 'bundler/setup'
|
8
|
-
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
9
8
|
require 'ib-ruby'
|
10
9
|
|
11
10
|
# Connect to IB as 0 (TWS) to retrieve all Orders, including TWS-generated ones
|
data/bin/market_data
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script connects to IB API and subscribes to market data for specific symbols
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# Definition of what we want market data for. We have to keep track of what ticker id
|
data/bin/option_data
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script subscribes to market data for a list of Options
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# Definition of what we want market data for. We have to keep track of what ticker id
|
data/bin/place_combo_order
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script places GOOG option butterfly combo order
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# Utility method that helps us build multi-legged (BAG) Orders
|
data/bin/place_order
CHANGED
@@ -3,8 +3,8 @@
|
|
3
3
|
# This script places WFC buy order for 100 lots
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
data/bin/template
CHANGED
@@ -2,12 +2,9 @@
|
|
2
2
|
#
|
3
3
|
# Your script description here...
|
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'
|
10
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
11
8
|
require 'ib-ruby'
|
12
9
|
|
13
10
|
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
data/bin/tick_data
CHANGED
@@ -3,14 +3,14 @@
|
|
3
3
|
# This script reproduces https://github.com/ib-ruby/ib-ruby/issues/12
|
4
4
|
|
5
5
|
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
6
|
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
8
8
|
require 'ib-ruby'
|
9
9
|
|
10
10
|
contract = IB::Contract.new :symbol=> 'AAPL',
|
11
11
|
:exchange=> "Smart",
|
12
12
|
:currency=> "USD",
|
13
|
-
:sec_type=>
|
13
|
+
:sec_type=> :stock,
|
14
14
|
:description=> "Some stock"
|
15
15
|
|
16
16
|
# First, connect to IB TWS. Arbitrary :client_id is used to identify your script
|
data/bin/time_and_sales
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# It then prints out all trades that exceed certain size.
|
5
5
|
|
6
6
|
require 'rubygems'
|
7
|
-
require 'pathname'
|
8
7
|
require 'bundler/setup'
|
8
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
9
9
|
require 'ib-ruby'
|
10
10
|
|
11
11
|
# Define the symbols we're interested in.
|
data/lib/ib-ruby.rb
CHANGED
@@ -1,4 +1,8 @@
|
|
1
1
|
module IB
|
2
|
+
# IB Models can be either database-backed, or not
|
3
|
+
# By default there is no DB backend, unless specifically requested
|
4
|
+
# require 'ib-ruby/db' # to make all IB models database-backed
|
5
|
+
DB ||= false
|
2
6
|
|
3
7
|
require 'ib-ruby/version'
|
4
8
|
require 'ib-ruby/extensions'
|
data/lib/ib-ruby/connection.rb
CHANGED
@@ -33,6 +33,10 @@ module IB
|
|
33
33
|
def initialize opts = {}
|
34
34
|
@options = DEFAULT_OPTIONS.merge(opts)
|
35
35
|
|
36
|
+
# A couple of locks to avoid race conditions in JRuby
|
37
|
+
@subscribe_lock = Mutex.new
|
38
|
+
@receive_lock = Mutex.new
|
39
|
+
|
36
40
|
self.default_logger = options[:logger] if options[:logger]
|
37
41
|
@connected = false
|
38
42
|
@next_order_id = nil
|
@@ -88,7 +92,7 @@ module IB
|
|
88
92
|
end
|
89
93
|
if connected?
|
90
94
|
socket.close
|
91
|
-
server = Hash.new
|
95
|
+
@server = Hash.new
|
92
96
|
@connected = false
|
93
97
|
end
|
94
98
|
end
|
@@ -109,40 +113,44 @@ module IB
|
|
109
113
|
# Listener will be called later with received message instance as its argument.
|
110
114
|
# Returns subscriber id to allow unsubscribing
|
111
115
|
def subscribe *args, &block
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
116
|
+
@subscribe_lock.synchronize do
|
117
|
+
subscriber = args.last.respond_to?(:call) ? args.pop : block
|
118
|
+
id = random_id
|
119
|
+
|
120
|
+
error "Need subscriber proc or block", :args unless subscriber.is_a? Proc
|
121
|
+
|
122
|
+
args.each do |what|
|
123
|
+
message_classes =
|
124
|
+
case
|
125
|
+
when what.is_a?(Class) && what < Messages::Incoming::AbstractMessage
|
126
|
+
[what]
|
127
|
+
when what.is_a?(Symbol)
|
128
|
+
[Messages::Incoming.const_get(what)]
|
129
|
+
when what.is_a?(Regexp)
|
130
|
+
Messages::Incoming::Classes.values.find_all { |klass| klass.to_s =~ what }
|
131
|
+
else
|
132
|
+
error "#{what} must represent incoming IB message class", :args
|
133
|
+
end
|
134
|
+
message_classes.flatten.each do |message_class|
|
135
|
+
# TODO: Fix: RuntimeError: can't add a new key into hash during iteration
|
136
|
+
subscribers[message_class][id] = subscriber
|
137
|
+
end
|
132
138
|
end
|
139
|
+
id
|
133
140
|
end
|
134
|
-
id
|
135
141
|
end
|
136
142
|
|
137
143
|
# Remove all subscribers with specific subscriber id (TODO: multiple ids)
|
138
144
|
def unsubscribe *ids
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
145
|
+
@subscribe_lock.synchronize do
|
146
|
+
removed = []
|
147
|
+
ids.each do |id|
|
148
|
+
removed_at_id = subscribers.map { |_, subscribers| subscribers.delete id }.compact
|
149
|
+
error "No subscribers with id #{id}" if removed_at_id.empty?
|
150
|
+
removed << removed_at_id
|
151
|
+
end
|
152
|
+
removed.flatten
|
144
153
|
end
|
145
|
-
removed.flatten
|
146
154
|
end
|
147
155
|
|
148
156
|
# Message subscribers. Key is the message class to listen for.
|
@@ -157,10 +165,12 @@ module IB
|
|
157
165
|
|
158
166
|
# Clear received messages Hash
|
159
167
|
def clear_received *message_types
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
168
|
+
@receive_lock.synchronize do
|
169
|
+
if message_types.empty?
|
170
|
+
received.each { |message_type, container| container.clear }
|
171
|
+
else
|
172
|
+
message_types.each { |message_type| received[message_type].clear }
|
173
|
+
end
|
164
174
|
end
|
165
175
|
end
|
166
176
|
|
@@ -243,14 +253,19 @@ module IB
|
|
243
253
|
# Create new instance of the appropriate message type,
|
244
254
|
# and have it read the message from server.
|
245
255
|
# NB: Failure here usually means unsupported message type received
|
256
|
+
error "Got unsupported message #{msg_id}" unless Messages::Incoming::Classes[msg_id]
|
246
257
|
msg = Messages::Incoming::Classes[msg_id].new(server)
|
247
258
|
|
248
259
|
# Deliver message to all registered subscribers, alert if no subscribers
|
249
|
-
|
260
|
+
@subscribe_lock.synchronize do
|
261
|
+
subscribers[msg.class].each { |_, subscriber| subscriber.call(msg) }
|
262
|
+
end
|
250
263
|
log.warn "No subscribers for message #{msg.class}!" if subscribers[msg.class].empty?
|
251
264
|
|
252
265
|
# Collect all received messages into a @received Hash
|
253
|
-
|
266
|
+
@receive_lock.synchronize do
|
267
|
+
received[msg.message_type] << msg if options[:received]
|
268
|
+
end
|
254
269
|
end
|
255
270
|
|
256
271
|
### Sending Outgoing messages to IB
|
@@ -277,6 +292,7 @@ module IB
|
|
277
292
|
# Place Order (convenience wrapper for send_message :PlaceOrder).
|
278
293
|
# Assigns client_id and order_id fields to placed order. Returns assigned order_id.
|
279
294
|
def place_order order, contract
|
295
|
+
error "Unable to place order, next_order_id not known" unless @next_order_id
|
280
296
|
order.client_id = server[:client_id]
|
281
297
|
order.order_id = @next_order_id
|
282
298
|
@next_order_id += 1
|