ib-ruby 0.4.20 → 0.4.22
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY +8 -0
- data/README.rdoc +16 -8
- data/VERSION +1 -1
- data/bin/historic_data +1 -2
- data/bin/time_and_sales +0 -4
- data/lib/ib-ruby/constants.rb +12 -3
- data/lib/ib-ruby/messages/incoming.rb +6 -9
- data/lib/ib-ruby/messages/outgoing.rb +46 -14
- data/lib/ib-ruby/models/contract.rb +0 -28
- data/lib/ib-ruby/models/order.rb +12 -0
- data/lib/ib-ruby/symbols/forex.rb +40 -41
- data/lib/ib-ruby/symbols/futures.rb +6 -8
- data/lib/ib-ruby/symbols/options.rb +2 -4
- data/lib/ib-ruby/symbols/stocks.rb +2 -2
- metadata +2 -9
- data/lib/legacy/bin/account_info_old +0 -36
- data/lib/legacy/bin/historic_data_old +0 -81
- data/lib/legacy/bin/market_data_old +0 -68
- data/lib/legacy/datatypes.rb +0 -485
- data/lib/legacy/ib-ruby.rb +0 -10
- data/lib/legacy/ib.rb +0 -226
- data/lib/legacy/messages.rb +0 -1458
@@ -1,81 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This script downloads historic data for specific symbol from IB
|
4
|
-
#
|
5
|
-
# TODO: Fix the Historical command line client
|
6
|
-
|
7
|
-
require 'pathname'
|
8
|
-
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
|
9
|
-
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
10
|
-
|
11
|
-
require 'rubygems'
|
12
|
-
require 'bundler/setup'
|
13
|
-
require 'ib-ruby'
|
14
|
-
|
15
|
-
### Configurable Options
|
16
|
-
Quiet = false # if Quiet == false, status data will be printed to STDERR
|
17
|
-
Timeout = 10 # How long to wait when no messages are received from TWS before exiting, in seconds
|
18
|
-
SymbolToRequest = IB::Symbols::Forex[:gbpusd]
|
19
|
-
|
20
|
-
# Definition of what we want market data for. We have to keep track
|
21
|
-
# of what ticker id corresponds to what symbol ourselves, because the
|
22
|
-
# ticks don't include any other identifying information.
|
23
|
-
#
|
24
|
-
# The choice of ticker ids is, as far as I can tell, arbitrary.
|
25
|
-
#
|
26
|
-
# Note that as of 4/07 there is no historical data available for forex spot.
|
27
|
-
#
|
28
|
-
@market = {123 => SymbolToRequest}
|
29
|
-
|
30
|
-
# To determine when the timeout has passed.
|
31
|
-
@last_msg_time = Time.now.to_i + 2
|
32
|
-
|
33
|
-
# Connect to IB TWS.
|
34
|
-
ib = IB::IB.new
|
35
|
-
|
36
|
-
# Uncomment this for verbose debug messages:
|
37
|
-
# IB::IBLogger.level = Logger::Severity::DEBUG
|
38
|
-
|
39
|
-
# Now, subscribe to HistoricalData incoming events. The code passed in the block
|
40
|
-
# will be executed when a message of that type is received, with the received
|
41
|
-
# message as its argument. In this case, we just print out the data.
|
42
|
-
#
|
43
|
-
# Note that we have to look the ticker id of each incoming message
|
44
|
-
# up in local memory to figure out what it's for.
|
45
|
-
#
|
46
|
-
# (N.B. The description field is not from IB TWS. It is defined
|
47
|
-
# locally in forex.rb, and is just arbitrary text.)
|
48
|
-
|
49
|
-
ib.subscribe(IB::IncomingMessages::HistoricalData, lambda { |msg|
|
50
|
-
|
51
|
-
STDERR.puts @market[msg.data[:req_id]].description + ": " + msg.data[:item_count].to_s("F") + " items:" unless Quiet
|
52
|
-
|
53
|
-
msg.data[:history].each { |datum|
|
54
|
-
|
55
|
-
@last_msg_time = Time.now.to_i
|
56
|
-
|
57
|
-
STDERR.puts " " + datum.to_s("F") unless Quiet
|
58
|
-
STDOUT.puts "#{datum.date},#{datum.open.to_s("F")},#{datum.high.to_s("F")},#{datum.low.to_s("F")},#{datum.close.to_s("F")},#{datum.volume}"
|
59
|
-
}
|
60
|
-
})
|
61
|
-
|
62
|
-
# Now we actually request historical data for the symbols we're
|
63
|
-
# interested in. TWS will respond with a HistoricalData message,
|
64
|
-
# which will be received by the code above.
|
65
|
-
|
66
|
-
@market.each_pair do |id, contract|
|
67
|
-
msg = IB::OutgoingMessages::RequestHistoricalData.new(:ticker_id => id,
|
68
|
-
:contract => contract,
|
69
|
-
:end_date_time => Time.now.to_ib,
|
70
|
-
:duration => (360).to_s, # how long before end_date_time to request in seconds - this means 1 day
|
71
|
-
:bar_size => IB::OutgoingMessages::RequestHistoricalData::BarSizes.index(:hour),
|
72
|
-
:what_to_show => :trades,
|
73
|
-
:use_RTH => 0,
|
74
|
-
:format_date => 2)
|
75
|
-
ib.dispatch(msg)
|
76
|
-
end
|
77
|
-
|
78
|
-
while true
|
79
|
-
exit(0) if Time.now.to_i > @last_msg_time + Timeout
|
80
|
-
sleep 1
|
81
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# This script connects to IB API, subscribes to market data for specific symbols
|
4
|
-
|
5
|
-
require 'rubygems'
|
6
|
-
require 'pathname'
|
7
|
-
require 'bundler/setup'
|
8
|
-
|
9
|
-
LIB_DIR = (Pathname.new(__FILE__).dirname + '../lib/').realpath.to_s
|
10
|
-
$LOAD_PATH.unshift LIB_DIR unless $LOAD_PATH.include?(LIB_DIR)
|
11
|
-
|
12
|
-
require 'ib-ruby'
|
13
|
-
|
14
|
-
# Definition of what we want market data for. We have to keep track
|
15
|
-
# of what ticker id corresponds to what symbol ourselves, because the
|
16
|
-
# ticks don't include any other identifying information.
|
17
|
-
#
|
18
|
-
# The choice of ticker ids is, as far as I can tell, arbitrary.
|
19
|
-
#
|
20
|
-
@market = {123 => IB::Symbols::Forex[:gbpusd],
|
21
|
-
456 => IB::Symbols::Forex[:eurusd],
|
22
|
-
789 => IB::Symbols::Forex[:usdcad]}
|
23
|
-
|
24
|
-
# First, connect to IB TWS.
|
25
|
-
ib = IB::IB.new
|
26
|
-
|
27
|
-
# Now, subscribe to TickerPrice and TickerSize events. The code
|
28
|
-
# passed in the block will be executed when a message of that type is
|
29
|
-
# received, with the received message as its argument. In this case,
|
30
|
-
# we just print out the tick.
|
31
|
-
#
|
32
|
-
# Note that we have to look the ticker id of each incoming message
|
33
|
-
# up in local memory to figure out what it's for.
|
34
|
-
#
|
35
|
-
# (N.B. The description field is not from IB TWS. It is defined
|
36
|
-
# locally in forex.rb, and is just arbitrary text.)
|
37
|
-
|
38
|
-
ib.subscribe(IB::IncomingMessages::TickPrice, lambda { |msg|
|
39
|
-
puts @market[msg.data[:ticker_id]].description + ": " + msg.to_human
|
40
|
-
})
|
41
|
-
|
42
|
-
ib.subscribe(IB::IncomingMessages::TickSize, lambda { |msg|
|
43
|
-
puts @market[msg.data[:ticker_id]].description + ": " + msg.to_human
|
44
|
-
})
|
45
|
-
|
46
|
-
|
47
|
-
# Now we actually request market data for the symbols we're interested in.
|
48
|
-
|
49
|
-
@market.each_pair { |id, contract|
|
50
|
-
msg = IB::OutgoingMessages::RequestMarketData.new({
|
51
|
-
:ticker_id => id,
|
52
|
-
:contract => contract
|
53
|
-
})
|
54
|
-
ib.dispatch(msg)
|
55
|
-
}
|
56
|
-
|
57
|
-
puts "\nSubscribed to market data"
|
58
|
-
puts "\n******** Press <Enter> to cancel... *********\n\n"
|
59
|
-
gets
|
60
|
-
puts "Cancelling market data subscription.."
|
61
|
-
|
62
|
-
@market.each_pair { |id, contract|
|
63
|
-
msg = IB::OutgoingMessages::CancelMarketData.new({
|
64
|
-
:ticker_id => id,
|
65
|
-
:contract => contract
|
66
|
-
})
|
67
|
-
ib.dispatch(msg)
|
68
|
-
}
|
data/lib/legacy/datatypes.rb
DELETED
@@ -1,485 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (C) 2006 Blue Voodoo Magic LLC.
|
3
|
-
#
|
4
|
-
# This library is free software; you can redistribute it and/or modify
|
5
|
-
# it under the terms of the GNU Lesser General Public License as
|
6
|
-
# published by the Free Software Foundation; either version 2.1 of the
|
7
|
-
# License, or (at your option) any later version.
|
8
|
-
#
|
9
|
-
# This library is distributed in the hope that it will be useful, but
|
10
|
-
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
-
# Lesser General Public License for more details.
|
13
|
-
#
|
14
|
-
# You should have received a copy of the GNU Lesser General Public
|
15
|
-
# License along with this library; if not, write to the Free Software
|
16
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
17
|
-
# 02110-1301 USA
|
18
|
-
#
|
19
|
-
|
20
|
-
#
|
21
|
-
# TODO: Implement equals() according to the criteria in IB's Java client.
|
22
|
-
#
|
23
|
-
|
24
|
-
module IB
|
25
|
-
|
26
|
-
module Datatypes
|
27
|
-
attr_reader :created_at
|
28
|
-
|
29
|
-
class AbstractDatum
|
30
|
-
|
31
|
-
def init
|
32
|
-
@created_at = Time.now
|
33
|
-
end
|
34
|
-
|
35
|
-
# If a hash is given, keys are taken as attribute names, values as data.
|
36
|
-
# The attrs of the instance are set automatically from the attributeHash.
|
37
|
-
#
|
38
|
-
# If no hash is given, #init is called in the instance. #init
|
39
|
-
# should set the datum up in a generic state.
|
40
|
-
#
|
41
|
-
def initialize(attributeHash=nil)
|
42
|
-
if attributeHash.nil?
|
43
|
-
init
|
44
|
-
else
|
45
|
-
raise ArgumentError.new("Argument must be a Hash") unless attributeHash.is_a?(Hash)
|
46
|
-
attributeHash.keys.each { |key|
|
47
|
-
self.send((key.to_s + "=").to_sym, attributeHash[key])
|
48
|
-
}
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end # AbstractDatum
|
52
|
-
|
53
|
-
|
54
|
-
# This is used within HistoricData messages.
|
55
|
-
# Instantiate with a Hash of attributes, to be auto-set via initialize in AbstractDatum.
|
56
|
-
class Bar < AbstractDatum
|
57
|
-
attr_accessor :date, :open, :high, :low, :close, :volume, :wap, :has_gaps
|
58
|
-
# :bar_count => @socket.read_int
|
59
|
-
|
60
|
-
def to_s
|
61
|
-
"<Bar: #{@date}; OHLC: #{@open.to_s}, #{@high.to_s}, #{@low.to_s}, #{@close.to_s}; volume: #{@volume}; wap: #{@wap.to_s}; has_gaps: #{@has_gaps}>"
|
62
|
-
end
|
63
|
-
end # Bar
|
64
|
-
|
65
|
-
|
66
|
-
class Order < AbstractDatum
|
67
|
-
# Constants used in Order objects. Drawn from Order.java
|
68
|
-
Origin_Customer = 0
|
69
|
-
Origin_Firm = 1
|
70
|
-
|
71
|
-
Opt_Unknown = '?'
|
72
|
-
Opt_Broker_Dealer = 'b'
|
73
|
-
Opt_Customer = 'c'
|
74
|
-
Opt_Firm = 'f'
|
75
|
-
Opt_Isemm = 'm'
|
76
|
-
Opt_Farmm = 'n'
|
77
|
-
Opt_Specialist = 'y'
|
78
|
-
|
79
|
-
OCA_Cancel_with_block = 1
|
80
|
-
OCA_Reduce_with_block = 2
|
81
|
-
OCA_Reduce_non_block = 3
|
82
|
-
|
83
|
-
# Box orders consts:
|
84
|
-
Box_Auction_Match = 1
|
85
|
-
Box_Auction_Improvement = 2
|
86
|
-
Box_Auction_Transparent = 3
|
87
|
-
|
88
|
-
# Volatility orders consts:
|
89
|
-
Volatility_Type_Daily = 1
|
90
|
-
Volatility_Type_Annual = 2
|
91
|
-
Volatility_Ref_Price_Average = 1
|
92
|
-
Volatility_Ref_Price_BidOrAsk = 2
|
93
|
-
|
94
|
-
# No idea why IB uses a large number as the default for some fields
|
95
|
-
Max_Value = 99999999
|
96
|
-
|
97
|
-
# Main order fields
|
98
|
-
attr_accessor :id, # int m_orderId; ?
|
99
|
-
:client_id, # int
|
100
|
-
:perm_id, # int
|
101
|
-
:action, # String
|
102
|
-
:total_quantity, # int
|
103
|
-
:order_type, # String
|
104
|
-
:limit_price, # double
|
105
|
-
:aux_price, # double
|
106
|
-
#:shares_allocation, # deprecated sharesAllocation field
|
107
|
-
|
108
|
-
# Extended order fields
|
109
|
-
:tif, # String: Time in Force - DAY, GTC, etc.
|
110
|
-
:oca_group, # String: one cancels all group name
|
111
|
-
:oca_type, # 1 = CANCEL_WITH_BLOCK, 2 = REDUCE_WITH_BLOCK, 3 = REDUCE_NON_BLOCK
|
112
|
-
:order_ref, # String
|
113
|
-
:transmit, # bool:if false, order will be created but not transmitted.
|
114
|
-
:parent_id, # int: Parent order id, to associate auto STP or TRAIL orders with the original order.
|
115
|
-
:block_order, # bool
|
116
|
-
:sweep_to_fill, # bool
|
117
|
-
:display_size, # int
|
118
|
-
:trigger_method, # 0=Default, 1=Double_Bid_Ask, 2=Last, 3=Double_Last,
|
119
|
-
# 4=Bid_Ask, 7=Last_or_Bid_Ask, 8=Mid-point
|
120
|
-
:outside_rth, # bool: WAS ignore_rth
|
121
|
-
:hidden, # bool
|
122
|
-
:good_after_time, # FORMAT: 20060505 08:00:00 {time zone}
|
123
|
-
:good_till_date, # FORMAT: 20060505 08:00:00 {time zone}
|
124
|
-
:override_percentage_constraints, # bool
|
125
|
-
:rule_80a, # Individual = 'I', Agency = 'A', AgentOtherMember = 'W',
|
126
|
-
# IndividualPTIA = 'J', AgencyPTIA = 'U', AgentOtherMemberPTIA = 'M',
|
127
|
-
# IndividualPT = 'K', AgencyPT = 'Y', AgentOtherMemberPT = 'N'
|
128
|
-
:all_or_none, # bool
|
129
|
-
:min_quantity, # int
|
130
|
-
:percent_offset, # double: REL orders only
|
131
|
-
:trail_stop_price, # double: for TRAILLIMIT orders only
|
132
|
-
|
133
|
-
# Financial advisors only, all Strings
|
134
|
-
:fa_group, :fa_profile, :fa_method, :fa_percentage,
|
135
|
-
|
136
|
-
# Institutional orders only
|
137
|
-
:open_close, # String: O=Open, C=Close
|
138
|
-
:origin, # int: 0=Customer, 1=Firm
|
139
|
-
:short_sale_slot, # 1 - you hold the shares, 2 - they will be delivered from elsewhere. Only for Action="SSHORT
|
140
|
-
:designated_location, # String: set when slot==2 only
|
141
|
-
:exempt_code, # int
|
142
|
-
|
143
|
-
# SMART routing only
|
144
|
-
:discretionary_amount, # double
|
145
|
-
:etrade_only, # bool
|
146
|
-
:firm_quote_only, # bool
|
147
|
-
:nbbo_price_cap, # double
|
148
|
-
|
149
|
-
# BOX or VOL ORDERS ONLY
|
150
|
-
:auction_strategy, # 1=AUCTION_MATCH, 2=AUCTION_IMPROVEMENT, 3=AUCTION_TRANSPARENT
|
151
|
-
:starting_price, # double, BOX ORDERS ONLY
|
152
|
-
:stock_ref_price, # double, BOX ORDERS ONLY
|
153
|
-
:delta, # double, BOX ORDERS ONLY
|
154
|
-
|
155
|
-
# Pegged to stock or VOL orders
|
156
|
-
:stock_range_lower, # double
|
157
|
-
:stock_range_upper, # double
|
158
|
-
|
159
|
-
# VOLATILITY ORDERS ONLY
|
160
|
-
:volatility, # double
|
161
|
-
:volatility_type, # int: 1=daily, 2=annual
|
162
|
-
:continuous_update, # int
|
163
|
-
:reference_price_type, # int: 1=Average, 2 = BidOrAsk
|
164
|
-
:delta_neutral_order_type, # String
|
165
|
-
:delta_neutral_aux_price, # double
|
166
|
-
|
167
|
-
# COMBO ORDERS ONLY
|
168
|
-
:basis_points, # double: EFP orders only
|
169
|
-
:basis_points_type, # double: EFP orders only
|
170
|
-
|
171
|
-
# SCALE ORDERS ONLY
|
172
|
-
:scale_init_level_size, # int
|
173
|
-
:scale_subs_level_size, # int
|
174
|
-
:scale_price_increment, # double
|
175
|
-
|
176
|
-
# Clearing info
|
177
|
-
:account, # String: IB account
|
178
|
-
:settling_firm, # String
|
179
|
-
:clearing_account, # String: True beneficiary of the order
|
180
|
-
:clearing_intent, # "" (Default), "IB", "Away", "PTA" (PostTrade)
|
181
|
-
|
182
|
-
# ALGO ORDERS ONLY
|
183
|
-
:algo_strategy, # String
|
184
|
-
:algo_params, # public Vector<TagValue> m_algoParams; ?!
|
185
|
-
|
186
|
-
# WTF?!
|
187
|
-
:what_if, #public boolean m_whatIf; // What-if
|
188
|
-
:not_held #public boolean m_notHeld; // Not Held
|
189
|
-
|
190
|
-
def init
|
191
|
-
super
|
192
|
-
|
193
|
-
@open_close = "0"
|
194
|
-
@origin = Origin_Customer
|
195
|
-
@transmit = true
|
196
|
-
@primary_exchange = ''
|
197
|
-
@designated_location = ''
|
198
|
-
@min_quantity = Max_Value # TODO: Initialize with nil instead of Max_Value, or change
|
199
|
-
# Order sending code in IB::Messages::Outgoing::PlaceOrder
|
200
|
-
@percent_offset = Max_Value # -"-
|
201
|
-
@nbba_price_cap = Max_Value # -"-
|
202
|
-
@starting_price = Max_Value # -"-
|
203
|
-
@stock_ref_price = Max_Value # -"-
|
204
|
-
@delta = Max_Value
|
205
|
-
@delta_neutral_order_type = ''
|
206
|
-
@delta_neutral_aux_price = Max_Value # -"-
|
207
|
-
@reference_price_type = Max_Value # -"-
|
208
|
-
end # init
|
209
|
-
|
210
|
-
end # class Order
|
211
|
-
|
212
|
-
|
213
|
-
class Contract < AbstractDatum
|
214
|
-
|
215
|
-
# Valid security types (sec_type attribute)
|
216
|
-
SECURITY_TYPES =
|
217
|
-
{
|
218
|
-
:stock => "STK",
|
219
|
-
:option => "OPT",
|
220
|
-
:future => "FUT",
|
221
|
-
:index => "IND",
|
222
|
-
:futures_option => "FOP",
|
223
|
-
:forex => "CASH",
|
224
|
-
:bag => "BAG"
|
225
|
-
}
|
226
|
-
|
227
|
-
# note that the :description field is entirely local to ib-ruby, and not part of TWS.
|
228
|
-
# You can use it to store whatever arbitrary data you want.
|
229
|
-
attr_accessor :symbol, :strike, :multiplier, :exchange, :currency,
|
230
|
-
:local_symbol, :combo_legs, :description
|
231
|
-
|
232
|
-
# Bond values
|
233
|
-
attr_accessor(:cusip, :ratings, :desc_append, :bond_type, :coupon_type, :callable,
|
234
|
-
:puttable, :coupon, :convertible, :maturity, :issue_date)
|
235
|
-
|
236
|
-
attr_reader :sec_type, :expiry, :right, :primary_exchange
|
237
|
-
|
238
|
-
|
239
|
-
# some protective filters
|
240
|
-
def primary_exchange=(x)
|
241
|
-
x.upcase! if x.is_a?(String)
|
242
|
-
|
243
|
-
# per http://chuckcaplan.com/twsapi/index.php/Class%20Contract
|
244
|
-
raise(ArgumentError.new("Don't set primary_exchange to smart")) if x == "SMART"
|
245
|
-
|
246
|
-
@primary_exchange = x
|
247
|
-
end
|
248
|
-
|
249
|
-
def right=(x)
|
250
|
-
x.upcase! if x.is_a?(String)
|
251
|
-
x = nil if !x.nil? && x.empty?
|
252
|
-
raise(ArgumentError.new("Invalid right \"#{x}\" (must be one of PUT, CALL, P, C)")) unless x.nil? || ["PUT", "CALL", "P", "C", "0"].include?(x)
|
253
|
-
@right = x
|
254
|
-
end
|
255
|
-
|
256
|
-
def expiry=(x)
|
257
|
-
x = x.to_s
|
258
|
-
if (x.nil? || !(x =~ /\d{6,8}/)) and !x.empty? then
|
259
|
-
raise ArgumentError.new("Invalid expiry \"#{x}\" (must be in format YYYYMM or YYYYMMDD)")
|
260
|
-
end
|
261
|
-
@expiry = x
|
262
|
-
end
|
263
|
-
|
264
|
-
def sec_type=(x)
|
265
|
-
x = nil if !x.nil? && x.empty?
|
266
|
-
raise(ArgumentError.new("Invalid security type \"#{x}\" (see SECURITY_TYPES constant in Contract class for valid types)")) unless x.nil? || SECURITY_TYPES.values.include?(x)
|
267
|
-
@sec_type = x
|
268
|
-
end
|
269
|
-
|
270
|
-
def reset
|
271
|
-
@combo_legs = Array.new
|
272
|
-
@strike = 0
|
273
|
-
end
|
274
|
-
|
275
|
-
# This returns an Array of data from the given contract, in standard format.
|
276
|
-
# Different messages serialize contracts differently. Go figure.
|
277
|
-
# Note that it does not include the combo legs.
|
278
|
-
def serialize(type = :long)
|
279
|
-
[self.symbol,
|
280
|
-
self.sec_type,
|
281
|
-
self.expiry,
|
282
|
-
self.strike,
|
283
|
-
self.right,
|
284
|
-
self.multiplier,
|
285
|
-
self.exchange] +
|
286
|
-
(type == :long ? [self.primary_exchange] : []) +
|
287
|
-
[self.currency,
|
288
|
-
self.local_symbol]
|
289
|
-
end
|
290
|
-
|
291
|
-
# @Legacy
|
292
|
-
def serialize_long(version)
|
293
|
-
serialize(:long)
|
294
|
-
end
|
295
|
-
|
296
|
-
# @Legacy
|
297
|
-
def serialize_short(version)
|
298
|
-
serialize(:short)
|
299
|
-
end
|
300
|
-
|
301
|
-
# This produces a string uniquely identifying this contract, in the format used
|
302
|
-
# for command line arguments in the IB-Ruby examples. The format is:
|
303
|
-
#
|
304
|
-
# symbol:security_type:expiry:strike:right:multiplier:exchange:primary_exchange:currency:local_symbol
|
305
|
-
#
|
306
|
-
# Fields not needed for a particular security should be left blank
|
307
|
-
# (e.g. strike and right are only relevant for options.)
|
308
|
-
#
|
309
|
-
# For example, to query the British pound futures contract trading on Globex
|
310
|
-
# expiring in September, 2008, the string is:
|
311
|
-
#
|
312
|
-
# GBP:FUT:200809:::62500:GLOBEX::USD:
|
313
|
-
def serialize_ib_ruby(version)
|
314
|
-
serialize.join(":")
|
315
|
-
end
|
316
|
-
|
317
|
-
# This returns a Contract initialized from the serialize_ib_ruby format string.
|
318
|
-
def self.from_ib_ruby(string)
|
319
|
-
c = Contract.new
|
320
|
-
c.symbol, c.sec_type, c.expiry, c.strike, c.right, c.multiplier,
|
321
|
-
c.exchange, c.primary_exchange, c.currency, c.local_symbol = string.split(":")
|
322
|
-
c
|
323
|
-
end
|
324
|
-
|
325
|
-
def serialize_under_comp(*args)
|
326
|
-
raise "Unimplemented"
|
327
|
-
# EClientSocket.java, line 471:
|
328
|
-
#if (m_serverVersion >= MIN_SERVER_VER_UNDER_COMP) {
|
329
|
-
# if (contract.m_underComp != null) {
|
330
|
-
# UnderComp underComp = contract.m_underComp;
|
331
|
-
# send( true);
|
332
|
-
# send( underComp.m_conId);
|
333
|
-
# send( underComp.m_delta);
|
334
|
-
# send( underComp.m_price);
|
335
|
-
# }
|
336
|
-
end
|
337
|
-
|
338
|
-
def serialize_algo(*args)
|
339
|
-
raise "Unimplemented"
|
340
|
-
#if (m_serverVersion >= MIN_SERVER_VER_ALGO_ORDERS) {
|
341
|
-
# send( order.m_algoStrategy);
|
342
|
-
# if( !IsEmpty(order.m_algoStrategy)) {
|
343
|
-
# java.util.Vector algoParams = order.m_algoParams;
|
344
|
-
# int algoParamsCount = algoParams == null ? 0 : algoParams.size();
|
345
|
-
# send( algoParamsCount);
|
346
|
-
# if( algoParamsCount > 0) {
|
347
|
-
# for( int i = 0; i < algoParamsCount; ++i) {
|
348
|
-
# TagValue tagValue = (TagValue)algoParams.get(i);
|
349
|
-
# send( tagValue.m_tag);
|
350
|
-
# send( tagValue.m_value);
|
351
|
-
# }
|
352
|
-
# }
|
353
|
-
# }
|
354
|
-
#}
|
355
|
-
end
|
356
|
-
|
357
|
-
# Some messages send open_close too, some don't. WTF.
|
358
|
-
def serialize_combo_legs(include_open_close = false)
|
359
|
-
if self.combo_legs.nil?
|
360
|
-
[0]
|
361
|
-
else
|
362
|
-
[self.combo_legs.size].concat(self.combo_legs.serialize(include_open_close))
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
def init
|
367
|
-
super
|
368
|
-
|
369
|
-
@combo_legs = Array.new
|
370
|
-
@strike = 0
|
371
|
-
@sec_type = ''
|
372
|
-
end
|
373
|
-
|
374
|
-
def to_human
|
375
|
-
"<IB-Contract: " + [symbol, expiry, sec_type, strike, right, exchange, currency].join("-") + "}>"
|
376
|
-
end
|
377
|
-
|
378
|
-
def to_short
|
379
|
-
"#{symbol}#{expiry}#{strike}#{right}#{exchange}#{currency}"
|
380
|
-
end
|
381
|
-
|
382
|
-
def to_s
|
383
|
-
to_human
|
384
|
-
end
|
385
|
-
|
386
|
-
end # class Contract
|
387
|
-
|
388
|
-
class ContractDetails < AbstractDatum
|
389
|
-
attr_accessor :summary, :market_name, :trading_class, :con_id, :min_tick,
|
390
|
-
:multiplier, :price_magnifier, :order_types, :valid_exchanges
|
391
|
-
|
392
|
-
def init
|
393
|
-
super
|
394
|
-
|
395
|
-
@summary = Contract.new
|
396
|
-
@con_id = 0
|
397
|
-
@min_tick = 0
|
398
|
-
end
|
399
|
-
end # class ContractDetails
|
400
|
-
|
401
|
-
class Execution < AbstractDatum
|
402
|
-
attr_accessor :order_id, :client_id, :exec_id, :time, :account_number, :exchange,
|
403
|
-
:side, :shares, :price, :perm_id, :liquidation
|
404
|
-
|
405
|
-
def init
|
406
|
-
super
|
407
|
-
|
408
|
-
@order_id = 0
|
409
|
-
@client_id = 0
|
410
|
-
@shares = 0
|
411
|
-
@price = 0
|
412
|
-
@perm_id = 0
|
413
|
-
@liquidation =0
|
414
|
-
end
|
415
|
-
end # Execution
|
416
|
-
|
417
|
-
# From EClientSocket.java: Note that the valid format for m_time is "yyyymmdd-hh:mm:ss"
|
418
|
-
class ExecutionFilter < AbstractDatum
|
419
|
-
attr_accessor :client_id, :acct_code, :time, :symbol, :sec_type, :exchange, :side
|
420
|
-
|
421
|
-
def init
|
422
|
-
super
|
423
|
-
|
424
|
-
@client_id = 0
|
425
|
-
end
|
426
|
-
|
427
|
-
end # ExecutionFilter
|
428
|
-
|
429
|
-
|
430
|
-
class ComboLeg < AbstractDatum
|
431
|
-
attr_accessor :con_id, :ratio, :action, :exchange, :open_close
|
432
|
-
|
433
|
-
def init
|
434
|
-
super
|
435
|
-
|
436
|
-
@con_id = 0
|
437
|
-
@ratio = 0
|
438
|
-
@open_close = 0
|
439
|
-
end
|
440
|
-
|
441
|
-
# Some messages include open_close, some don't. wtf.
|
442
|
-
def serialize(include_open_close = false)
|
443
|
-
self.map { |leg|
|
444
|
-
[leg.con_id,
|
445
|
-
leg.ratio,
|
446
|
-
leg.action,
|
447
|
-
leg.exchange,
|
448
|
-
(include_open_close ? leg.open_close : [])]
|
449
|
-
}.flatten
|
450
|
-
end
|
451
|
-
end # ComboLeg
|
452
|
-
|
453
|
-
|
454
|
-
class ScannerSubscription < AbstractDatum
|
455
|
-
|
456
|
-
attr_accessor :number_of_rows, :instrument, :location_code, :scan_code, :above_price,
|
457
|
-
:below_price, :above_volume, :average_option_volume_above,
|
458
|
-
:market_cap_above, :market_cap_below, :moody_rating_above,
|
459
|
-
:moody_rating_below, :sp_rating_above, :sp_rating_below,
|
460
|
-
:maturity_date_above, :maturity_date_below, :coupon_rate_above,
|
461
|
-
:coupon_rate_below, :exclude_convertible, :scanner_setting_pairs,
|
462
|
-
:stock_type_filter
|
463
|
-
|
464
|
-
def init
|
465
|
-
super
|
466
|
-
|
467
|
-
@coupon_rate_above = @coupon_rate_below = @market_cap_below = @market_cap_above =
|
468
|
-
@average_option_volume_above = @above_volume = @below_price = @above_price = nil
|
469
|
-
@number_of_rows = -1 # none specified, per ScannerSubscription.java
|
470
|
-
end
|
471
|
-
end # ScannerSubscription
|
472
|
-
|
473
|
-
|
474
|
-
# Just like a Hash, but throws an exception if you try to access a key that doesn't exist.
|
475
|
-
class StringentHash < Hash
|
476
|
-
def initialize(hash)
|
477
|
-
super() { |hash, key| raise Exception.new("key #{key.inspect} not found!") }
|
478
|
-
self.merge!(hash) unless hash.nil?
|
479
|
-
end
|
480
|
-
end
|
481
|
-
|
482
|
-
end # module Datatypes
|
483
|
-
Models = Datatypes
|
484
|
-
|
485
|
-
end # module
|