ib-api 972.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +50 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +105 -0
- data/Guardfile +24 -0
- data/LICENSE +674 -0
- data/README.md +65 -0
- data/Rakefile +11 -0
- data/VERSION +1 -0
- data/api.gemspec +43 -0
- data/bin/console +95 -0
- data/bin/console.yml +3 -0
- data/bin/setup +8 -0
- data/changelog.md +7 -0
- data/example/README.md +76 -0
- data/example/account_info +54 -0
- data/example/account_positions +30 -0
- data/example/account_summary +88 -0
- data/example/cancel_orders +74 -0
- data/example/fa_accounts +25 -0
- data/example/fundamental_data +40 -0
- data/example/historic_data_cli +186 -0
- data/example/list_orders +45 -0
- data/example/portfolio_csv +81 -0
- data/example/scanner_data +62 -0
- data/example/template +19 -0
- data/example/tick_data +28 -0
- data/lib/extensions/class-extensions.rb +87 -0
- data/lib/ib-api.rb +7 -0
- data/lib/ib/base.rb +103 -0
- data/lib/ib/base_properties.rb +160 -0
- data/lib/ib/connection.rb +450 -0
- data/lib/ib/constants.rb +393 -0
- data/lib/ib/errors.rb +44 -0
- data/lib/ib/logger.rb +26 -0
- data/lib/ib/messages.rb +99 -0
- data/lib/ib/messages/abstract_message.rb +101 -0
- data/lib/ib/messages/incoming.rb +251 -0
- data/lib/ib/messages/incoming/abstract_message.rb +116 -0
- data/lib/ib/messages/incoming/account_value.rb +78 -0
- data/lib/ib/messages/incoming/alert.rb +34 -0
- data/lib/ib/messages/incoming/contract_data.rb +102 -0
- data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
- data/lib/ib/messages/incoming/execution_data.rb +50 -0
- data/lib/ib/messages/incoming/historical_data.rb +84 -0
- data/lib/ib/messages/incoming/market_depths.rb +44 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
- data/lib/ib/messages/incoming/open_order.rb +277 -0
- data/lib/ib/messages/incoming/order_status.rb +85 -0
- data/lib/ib/messages/incoming/portfolio_value.rb +78 -0
- data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib/messages/incoming/scanner_data.rb +54 -0
- data/lib/ib/messages/incoming/ticks.rb +268 -0
- data/lib/ib/messages/outgoing.rb +437 -0
- data/lib/ib/messages/outgoing/abstract_message.rb +88 -0
- data/lib/ib/messages/outgoing/account_requests.rb +112 -0
- data/lib/ib/messages/outgoing/bar_requests.rb +250 -0
- data/lib/ib/messages/outgoing/place_order.rb +209 -0
- data/lib/ib/messages/outgoing/request_marketdata.rb +99 -0
- data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
- data/lib/ib/model.rb +4 -0
- data/lib/ib/models.rb +14 -0
- data/lib/ib/server_versions.rb +114 -0
- data/lib/ib/socket.rb +185 -0
- data/lib/ib/support.rb +160 -0
- data/lib/ib/version.rb +6 -0
- data/lib/models/ib/account.rb +85 -0
- data/lib/models/ib/account_value.rb +33 -0
- data/lib/models/ib/bag.rb +55 -0
- data/lib/models/ib/bar.rb +31 -0
- data/lib/models/ib/combo_leg.rb +105 -0
- data/lib/models/ib/condition.rb +245 -0
- data/lib/models/ib/contract.rb +415 -0
- data/lib/models/ib/contract_detail.rb +108 -0
- data/lib/models/ib/execution.rb +67 -0
- data/lib/models/ib/forex.rb +13 -0
- data/lib/models/ib/future.rb +15 -0
- data/lib/models/ib/index.rb +15 -0
- data/lib/models/ib/option.rb +78 -0
- data/lib/models/ib/option_detail.rb +55 -0
- data/lib/models/ib/order.rb +519 -0
- data/lib/models/ib/order_state.rb +152 -0
- data/lib/models/ib/portfolio_value.rb +64 -0
- data/lib/models/ib/stock.rb +16 -0
- data/lib/models/ib/underlying.rb +34 -0
- data/lib/models/ib/vertical.rb +96 -0
- data/lib/requires.rb +12 -0
- metadata +203 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'ib/messages/abstract_message'
|
2
|
+
require 'ib/support'
|
3
|
+
require 'ox'
|
4
|
+
module IB
|
5
|
+
module Messages
|
6
|
+
module Incoming
|
7
|
+
using IBSupport # refine Array-method for decoding of IB-Messages
|
8
|
+
|
9
|
+
|
10
|
+
# Container for specific message classes, keyed by their message_ids
|
11
|
+
Classes = {}
|
12
|
+
|
13
|
+
class AbstractMessage < IB::Messages::AbstractMessage
|
14
|
+
|
15
|
+
attr_accessor :buffer # is an array
|
16
|
+
|
17
|
+
def version # Per message, received messages may have the different versions
|
18
|
+
@data[:version]
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_version actual, expected
|
22
|
+
unless actual == expected || expected.is_a?(Array) && expected.include?(actual)
|
23
|
+
puts self.class.name
|
24
|
+
error "Unsupported version #{actual} received, expected #{expected}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create incoming message from a given source (IB Socket or data Hash)
|
29
|
+
def initialize source
|
30
|
+
@created_at = Time.now
|
31
|
+
if source.is_a?(Hash) # Source is a @data Hash
|
32
|
+
@data = source
|
33
|
+
@buffer =[] # initialize empty buffer, indicates a successfull initializing
|
34
|
+
else
|
35
|
+
@buffer = source
|
36
|
+
### DEBUG DEBUG DEBUG RAW STREAM ###############
|
37
|
+
# if uncommented, the raw-input from the tws is included in the logging
|
38
|
+
# puts "BUFFER :> #{buffer.inspect} "
|
39
|
+
### DEBUG DEBUG DEBUG RAW STREAM ###############
|
40
|
+
@data = Hash.new
|
41
|
+
self.load
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid?
|
46
|
+
@buffer.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
## more recent messages omit the transmission of a version
|
50
|
+
## thus just load the parameter-map
|
51
|
+
def simple_load
|
52
|
+
load_map *self.class.data_map
|
53
|
+
rescue IB::Error => e
|
54
|
+
error "Reading #{self.class}: #{e.class}: #{e.message}", :load, e.backtrace
|
55
|
+
end
|
56
|
+
# Every message loads received message version first
|
57
|
+
# Override the load method in your subclass to do actual reading into @data.
|
58
|
+
def load
|
59
|
+
unless self.class.version.zero?
|
60
|
+
@data[:version] = buffer.read_int
|
61
|
+
check_version @data[:version], self.class.version
|
62
|
+
end
|
63
|
+
simple_load
|
64
|
+
end
|
65
|
+
|
66
|
+
# Load @data from the buffer according to the given data map.
|
67
|
+
#
|
68
|
+
# map is a series of Arrays in the format of
|
69
|
+
# [ :name, :type ], [ :group, :name, :type]
|
70
|
+
# type identifiers must have a corresponding read_type method on the buffer-class (read_int, etc.).
|
71
|
+
# group is used to lump together aggregates, such as Contract or Order fields
|
72
|
+
def load_map(*map)
|
73
|
+
map.each do |instruction|
|
74
|
+
# We determine the function of the first element
|
75
|
+
head = instruction.first
|
76
|
+
case head
|
77
|
+
when Integer # >= Version condition: [ min_version, [map]]
|
78
|
+
load_map *instruction.drop(1) if version >= head
|
79
|
+
|
80
|
+
when Proc # Callable condition: [ condition, [map]]
|
81
|
+
load_map *instruction.drop(1) if head.call
|
82
|
+
|
83
|
+
when true # Pre-condition already succeeded!
|
84
|
+
load_map *instruction.drop(1)
|
85
|
+
|
86
|
+
when nil, false # Pre-condition already failed! Do nothing...
|
87
|
+
|
88
|
+
when Symbol # Normal map
|
89
|
+
group, name, type, block =
|
90
|
+
if instruction[2].nil? || instruction[2].is_a?(Proc) # lambda's are Proc's
|
91
|
+
[nil] + instruction # No group, [ :name, :type, (:block) ]
|
92
|
+
else
|
93
|
+
instruction # [ :group, :name, :type, (:block)]
|
94
|
+
end
|
95
|
+
begin
|
96
|
+
data = @buffer.__send__("read_#{type}", &block)
|
97
|
+
rescue IB::LoadError, NoMethodError => e
|
98
|
+
error "Reading #{self.class}: #{e.class}: #{e.message} --> Instruction: #{name}" , :reader, false
|
99
|
+
end
|
100
|
+
# debug puts data.inspect
|
101
|
+
if group
|
102
|
+
@data[group] ||= {}
|
103
|
+
@data[group][name] = data
|
104
|
+
else
|
105
|
+
@data[name] = data
|
106
|
+
end
|
107
|
+
else
|
108
|
+
error "Unrecognized instruction #{instruction}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end # class AbstractMessage
|
114
|
+
end # module Incoming
|
115
|
+
end # module Messages
|
116
|
+
end # module IB
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
|
5
|
+
AccountUpdateTime = def_message 8, [:time_stamp, :string]
|
6
|
+
|
7
|
+
ManagedAccounts =
|
8
|
+
def_message 15, [:accounts_list, :string]
|
9
|
+
|
10
|
+
class ManagedAccounts
|
11
|
+
def accounts
|
12
|
+
accounts_list.split(',').map{|a| Account.new account: a}
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_human
|
16
|
+
"< ManagedAccounts: #{accounts.map(&:account).join(" - ")}>"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Receives previously requested FA configuration information from TWS.
|
21
|
+
ReceiveFA =
|
22
|
+
def_message 16, [:type, :int], # type of Financial Advisor configuration data
|
23
|
+
# being received from TWS. Valid values include:
|
24
|
+
# 1 = GROUPS, 2 = PROFILE, 3 = ACCOUNT ALIASES
|
25
|
+
[:xml, :xml] # XML string with requested FA configuration information.
|
26
|
+
|
27
|
+
class ReceiveFA
|
28
|
+
def accounts
|
29
|
+
xml[:ListOfAccountAliases][:AccountAlias].map{|x| Account.new x }
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_human
|
33
|
+
"<FA: #{accounts.map(&:to_human).join(" - ")}>"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
|
39
|
+
class AccountMessage < AbstractMessage
|
40
|
+
def account_value
|
41
|
+
@account_value = IB::AccountValue.new @data[:account_value]
|
42
|
+
end
|
43
|
+
def account_name
|
44
|
+
@account_name = @data[:account]
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_human
|
48
|
+
"<AccountValue: #{account_name}, #{account_value}"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
AccountSummary = def_message(63, AccountMessage,
|
52
|
+
[:request_id, :int],
|
53
|
+
[ :account, :string ],
|
54
|
+
[:account_value, :key, :symbol],
|
55
|
+
[:account_value, :value, :string],
|
56
|
+
[:account_value, :currency, :string]
|
57
|
+
)
|
58
|
+
AccountSummaryEnd = def_message(64)
|
59
|
+
|
60
|
+
AccountValue = def_message([6, 2], AccountMessage,
|
61
|
+
[:account_value, :key, :symbol],
|
62
|
+
[:account_value, :value, :string],
|
63
|
+
[:account_value, :currency, :string],
|
64
|
+
[:account, :string])
|
65
|
+
|
66
|
+
|
67
|
+
AccountUpdatesMulti = def_message( 73,
|
68
|
+
[ :request_id, :int ],
|
69
|
+
[ :account , :string ],
|
70
|
+
[ :model, :string ],
|
71
|
+
[ :key , :string ],
|
72
|
+
[ :value , :decimal],
|
73
|
+
[ :currency, :string ])
|
74
|
+
|
75
|
+
AccountUpdatesMultiEnd = def_message 74
|
76
|
+
end # module Incoming
|
77
|
+
end # module Messages
|
78
|
+
end # module IB
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
|
5
|
+
# Called Error in Java code, but in fact this type of messages also
|
6
|
+
# deliver system alerts and additional (non-error) info from TWS.
|
7
|
+
ErrorMessage = Error = Alert = def_message([4, 2],
|
8
|
+
[:error_id, :int],
|
9
|
+
[:code, :int],
|
10
|
+
[:message, :string])
|
11
|
+
class Alert
|
12
|
+
# Is it an Error message?
|
13
|
+
def error?
|
14
|
+
code < 1000
|
15
|
+
end
|
16
|
+
|
17
|
+
# Is it a System message?
|
18
|
+
def system?
|
19
|
+
code > 1000 && code < 2000
|
20
|
+
end
|
21
|
+
|
22
|
+
# Is it a Warning message?
|
23
|
+
def warning?
|
24
|
+
code > 2000
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_human
|
28
|
+
"TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'} #{code}: #{message}"
|
29
|
+
end
|
30
|
+
end # class Alert
|
31
|
+
|
32
|
+
end # module Incoming
|
33
|
+
end # module Messages
|
34
|
+
end # module IB
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
module ContractAccessors
|
5
|
+
|
6
|
+
end
|
7
|
+
|
8
|
+
ContractDetails = ContractData =
|
9
|
+
def_message([10, [6, 8]],
|
10
|
+
[:request_id, :int], ## request id
|
11
|
+
[:contract, :symbol, :string], ## next the major contract-fields
|
12
|
+
[:contract, :sec_type, :string], ## are transmitted
|
13
|
+
[:contract, :last_trading_day, :date], ## difference to the array.get_contract
|
14
|
+
[:contract, :strike, :decimal], ## method: con_id is transmitted
|
15
|
+
[:contract, :right, :string], ## AFTER the main fields
|
16
|
+
[:contract, :exchange, :string], ##
|
17
|
+
[:contract, :currency, :string], ## thus we have to read the fields separately
|
18
|
+
[:contract, :local_symbol, :string],
|
19
|
+
[:contract_detail, :market_name, :string], ## extended
|
20
|
+
[:contract, :trading_class, :string], ## new Version 8
|
21
|
+
[:contract, :con_id, :int],
|
22
|
+
[:contract_detail, :min_tick, :decimal],
|
23
|
+
[:contract_detail, :md_size_multiplier, :int],
|
24
|
+
[:contract, :multiplier, :int],
|
25
|
+
[:contract_detail, :order_types, :string],
|
26
|
+
[:contract_detail, :valid_exchanges, :string],
|
27
|
+
[:contract_detail, :price_magnifier, :int],
|
28
|
+
[:contract_detail, :under_con_id, :int],
|
29
|
+
[:contract_detail, :long_name, :string],
|
30
|
+
[:contract, :primary_exchange, :string],
|
31
|
+
[:contract_detail, :contract_month, :string],
|
32
|
+
[:contract_detail, :industry, :string],
|
33
|
+
[:contract_detail, :category, :string],
|
34
|
+
[:contract_detail, :subcategory, :string],
|
35
|
+
[:contract_detail, :time_zone, :string],
|
36
|
+
[:contract_detail, :trading_hours, :string],
|
37
|
+
[:contract_detail, :liquid_hours, :string],
|
38
|
+
[:contract_detail, :ev_rule, :decimal],
|
39
|
+
[:contract_detail, :ev_multipler, :string],
|
40
|
+
[:contract_detail, :sec_id_list,:hash],
|
41
|
+
[:contract_detail, :agg_group, :int ],
|
42
|
+
[:contract_detail, :under_symbol, :string ],
|
43
|
+
[:contract_detail, :under_sec_type, :string ],
|
44
|
+
[:contract_detail, :market_rule_ids, :string ],
|
45
|
+
[:contract_detail, :real_expiration_date, :date ]
|
46
|
+
)
|
47
|
+
#
|
48
|
+
#
|
49
|
+
class ContractData
|
50
|
+
using IBSupport # defines tws-method for Array (socket.rb)
|
51
|
+
def contract
|
52
|
+
@contract = IB::Contract.build @data[:contract].merge(:contract_detail => contract_detail)
|
53
|
+
end
|
54
|
+
|
55
|
+
def contract_detail
|
56
|
+
@contract_detail = IB::ContractDetail.new @data[:contract_detail]
|
57
|
+
end
|
58
|
+
|
59
|
+
alias contract_details contract_detail
|
60
|
+
|
61
|
+
def to_human
|
62
|
+
"<Contract #{contract.to_human} #{contract_detail.to_human}>"
|
63
|
+
end
|
64
|
+
|
65
|
+
end # ContractData
|
66
|
+
|
67
|
+
BondContractData =
|
68
|
+
def_message [18, [4, 6]], ContractData,
|
69
|
+
[:request_id, :int],
|
70
|
+
[:contract, :symbol, :string],
|
71
|
+
[:contract, :sec_type, :string],
|
72
|
+
[:contract_detail, :cusip, :string],
|
73
|
+
[:contract_detail, :coupon, :decimal],
|
74
|
+
[:contract_detail, :maturity, :string],
|
75
|
+
[:contract_detail, :issue_date, :string],
|
76
|
+
[:contract_detail, :ratings, :string],
|
77
|
+
[:contract_detail, :bond_type, :string],
|
78
|
+
[:contract_detail, :coupon_type, :string],
|
79
|
+
[:contract_detail, :convertible, :boolean],
|
80
|
+
[:contract_detail, :callable, :boolean],
|
81
|
+
[:contract_detail, :puttable, :boolean],
|
82
|
+
[:contract_detail, :desc_append, :string],
|
83
|
+
[:contract, :exchange, :string],
|
84
|
+
[:contract, :currency, :string],
|
85
|
+
[:contract_detail, :market_name, :string], # extended
|
86
|
+
[:contract_detail, :trading_class, :string],
|
87
|
+
[:contract, :con_id, :int],
|
88
|
+
[:contract_detail, :min_tick, :decimal],
|
89
|
+
[:contract_detail, :order_types, :string],
|
90
|
+
[:contract_detail, :valid_exchanges, :string],
|
91
|
+
[:contract_detail, :valid_next_option_date, :string],
|
92
|
+
[:contract_detail, :valid_next_option_type, :string],
|
93
|
+
[:contract_detail, :valid_next_option_partial, :string],
|
94
|
+
[:contract_detail, :notes, :string],
|
95
|
+
[:contract_detail, :long_name, :string],
|
96
|
+
[:contract_detail, :ev_rule, :decimal],
|
97
|
+
[:contract_detail, :ev_multipler, :string],
|
98
|
+
[:sec_id_list_count, :int]
|
99
|
+
|
100
|
+
end # module Incoming
|
101
|
+
end # module Messages
|
102
|
+
end # module IB
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
|
5
|
+
# The server sends this message upon accepting a Delta-Neutral DN RFQ
|
6
|
+
# - see API Reference p. 26
|
7
|
+
DeltaNeutralValidation = def_message 56,
|
8
|
+
[:request_id, :int],
|
9
|
+
[:underlying, :con_id, :int],
|
10
|
+
[:underlying, :delta, :decimal],
|
11
|
+
[:underlying, :price, :decimal]
|
12
|
+
class DeltaNeutralValidation
|
13
|
+
def underlying
|
14
|
+
@underlying = IB::Underlying.new @data[:underlying]
|
15
|
+
end
|
16
|
+
|
17
|
+
alias under_comp underlying
|
18
|
+
|
19
|
+
end # DeltaNeutralValidation
|
20
|
+
|
21
|
+
end # module Incoming
|
22
|
+
end # module Messages
|
23
|
+
end # module IB
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
|
5
|
+
ExecutionData =
|
6
|
+
def_message [11, 0] , # [8, 9]],
|
7
|
+
# The reqID that was specified previously in the call to reqExecution()
|
8
|
+
[:request_id, :int],
|
9
|
+
[:execution, :local_id, :int],
|
10
|
+
[:contract, :contract],
|
11
|
+
[:execution, :exec_id, :string], # Weird format
|
12
|
+
[:execution, :time, :datetime],
|
13
|
+
[:execution, :account_name, :string],
|
14
|
+
[:execution, :exchange, :string],
|
15
|
+
[:execution, :side, :string],
|
16
|
+
[:execution, :quantity, :decimal],
|
17
|
+
[:execution, :price, :decimal],
|
18
|
+
[:execution, :perm_id, :int],
|
19
|
+
[:execution, :client_id, :int],
|
20
|
+
[:execution, :liquidation, :int],
|
21
|
+
[:execution, :cumulative_quantity, :int],
|
22
|
+
[:execution, :average_price, :decimal],
|
23
|
+
[:execution, :order_ref, :string],
|
24
|
+
[:execution, :ev_rule, :string],
|
25
|
+
[:execution, :ev_multiplier, :decimal],
|
26
|
+
[:execution, :model_code, :string],
|
27
|
+
[:execution, :last_liquidity, :int]
|
28
|
+
|
29
|
+
class ExecutionData
|
30
|
+
|
31
|
+
def load
|
32
|
+
simple_load
|
33
|
+
end
|
34
|
+
|
35
|
+
def contract
|
36
|
+
@contract = IB::Contract.build @data[:contract]
|
37
|
+
end
|
38
|
+
|
39
|
+
def execution
|
40
|
+
@execution = IB::Execution.new @data[:execution]
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_human
|
44
|
+
"<ExecutionData #{request_id}: #{contract.to_human}, #{execution}>"
|
45
|
+
end
|
46
|
+
|
47
|
+
end # ExecutionData
|
48
|
+
end # module Incoming
|
49
|
+
end # module Messages
|
50
|
+
end # module IB
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module IB
|
2
|
+
module Messages
|
3
|
+
module Incoming
|
4
|
+
|
5
|
+
# HistoricalData contains following @data:
|
6
|
+
#
|
7
|
+
# _General_:
|
8
|
+
#
|
9
|
+
# - request_id - The ID of the request to which this is responding
|
10
|
+
# - count - Number of Historical data points returned (size of :results).
|
11
|
+
# - results - an Array of Historical Data Bars
|
12
|
+
# - start_date - beginning of returned Historical data period
|
13
|
+
# - end_date - end of returned Historical data period
|
14
|
+
#
|
15
|
+
# Each returned Bar in @data[:results] Array contains this data:
|
16
|
+
# - date - The date-time stamp of the start of the bar. The format is set to sec since EPOCHE
|
17
|
+
# in outgoing/bar_requests ReqHistoricalData.
|
18
|
+
# - open - The bar opening price.
|
19
|
+
# - high - The high price during the time covered by the bar.
|
20
|
+
# - low - The low price during the time covered by the bar.
|
21
|
+
# - close - The bar closing price.
|
22
|
+
# - volume - The volume during the time covered by the bar.
|
23
|
+
# - trades - When TRADES historical data is returned, represents number of trades
|
24
|
+
# that occurred during the time period the bar covers
|
25
|
+
# - wap - The weighted average price during the time covered by the bar.
|
26
|
+
|
27
|
+
|
28
|
+
HistoricalData = def_message [17,0],
|
29
|
+
[:request_id, :int],
|
30
|
+
[:start_date, :datetime],
|
31
|
+
[:end_date, :datetime],
|
32
|
+
[:count, :int]
|
33
|
+
class HistoricalData
|
34
|
+
attr_accessor :results
|
35
|
+
using IBSupport # extended Array-Class from abstract_message
|
36
|
+
|
37
|
+
def load
|
38
|
+
super
|
39
|
+
|
40
|
+
@results = Array.new(@data[:count]) do |_|
|
41
|
+
IB::Bar.new :time => buffer.read_int_date, # conversion of epoche-time-integer to Dateime
|
42
|
+
# requires format_date in request to be "2"
|
43
|
+
# (outgoing/bar_requests # RequestHistoricalData#Encoding)
|
44
|
+
:open => buffer.read_decimal,
|
45
|
+
:high => buffer.read_decimal,
|
46
|
+
:low => buffer.read_decimal,
|
47
|
+
:close => buffer.read_decimal,
|
48
|
+
:volume => buffer.read_int,
|
49
|
+
:wap => buffer.read_decimal,
|
50
|
+
# :has_gaps => buffer.read_string, # only in ServerVersion < 124
|
51
|
+
:trades => buffer.read_int
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_human
|
56
|
+
"<HistoricalData: #{request_id}, #{count} items, #{start_date} to #{end_date}>"
|
57
|
+
end
|
58
|
+
end # HistoricalData
|
59
|
+
|
60
|
+
|
61
|
+
HistogramData = def_message( [89,0],
|
62
|
+
[:request_id, :int],
|
63
|
+
[ :number_of_points , :int ]) do
|
64
|
+
# to human
|
65
|
+
"<HistogramData: #{request_id}, #{number_of_points} read>"
|
66
|
+
end
|
67
|
+
|
68
|
+
class HistogramData
|
69
|
+
attr_accessor :results
|
70
|
+
using IBSupport # extended Array-Class from abstract_message
|
71
|
+
|
72
|
+
def load
|
73
|
+
super
|
74
|
+
|
75
|
+
@results = Array.new(@data[:number_of_points]) do |_|
|
76
|
+
{ price: buffer.read_decimal,
|
77
|
+
count: buffer.read_int }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end # module Incoming
|
83
|
+
end # module Messages
|
84
|
+
end # module IB
|