ib-api 10.33.4 → 972.0
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.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/Gemfile +2 -3
- data/Gemfile.lock +52 -67
- data/README.md +8 -60
- data/VERSION +1 -1
- data/api.gemspec +3 -10
- data/bin/console +38 -39
- data/bin/console.yml +2 -2
- data/changelog.md +0 -25
- 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/base.rb +1 -7
- data/lib/ib/base_properties.rb +12 -30
- data/lib/ib/connection.rb +269 -418
- data/lib/ib/constants.rb +22 -31
- data/lib/ib/errors.rb +1 -9
- data/lib/ib/logger.rb +26 -0
- data/lib/ib/messages/abstract_message.rb +43 -10
- data/lib/ib/messages/incoming/abstract_message.rb +98 -98
- data/lib/ib/messages/incoming/account_value.rb +78 -0
- data/lib/ib/messages/incoming/alert.rb +4 -4
- data/lib/ib/messages/incoming/contract_data.rb +29 -32
- data/lib/ib/messages/incoming/execution_data.rb +3 -3
- data/lib/ib/messages/incoming/historical_data.rb +33 -14
- data/lib/ib/messages/incoming/{market_depth.rb → market_depths.rb} +10 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +0 -1
- data/lib/ib/messages/incoming/open_order.rb +201 -214
- data/lib/ib/messages/incoming/order_status.rb +1 -1
- data/lib/ib/messages/incoming/portfolio_value.rb +58 -27
- data/lib/ib/messages/incoming/scanner_data.rb +1 -1
- data/lib/ib/messages/incoming/ticks.rb +268 -0
- data/lib/ib/messages/incoming.rb +95 -136
- data/lib/ib/messages/outgoing/abstract_message.rb +22 -18
- data/lib/ib/messages/outgoing/{request_account_summary.rb → account_requests.rb} +40 -7
- data/lib/ib/messages/outgoing/{bar_request_message.rb → bar_requests.rb} +16 -13
- data/lib/ib/messages/outgoing/place_order.rb +198 -138
- data/lib/ib/messages/outgoing/{request_market_data.rb → request_marketdata.rb} +29 -32
- data/lib/ib/messages/outgoing/request_tick_data.rb +21 -0
- data/lib/ib/messages/outgoing.rb +160 -133
- data/lib/ib/messages.rb +7 -47
- data/lib/ib/model.rb +4 -0
- data/lib/ib/models.rb +14 -0
- data/lib/{server_versions.rb → ib/server_versions.rb} +9 -40
- data/lib/ib/socket.rb +147 -45
- data/lib/ib/support.rb +158 -240
- data/lib/ib/version.rb +1 -1
- data/lib/ib-api.rb +5 -42
- data/lib/models/ib/account.rb +85 -0
- data/{models → lib/models}/ib/account_value.rb +5 -5
- data/{models → lib/models}/ib/bag.rb +7 -7
- data/{models → lib/models}/ib/bar.rb +2 -2
- data/{models → lib/models}/ib/combo_leg.rb +4 -26
- data/lib/models/ib/condition.rb +245 -0
- data/{models → lib/models}/ib/contract.rb +170 -166
- data/{models → lib/models}/ib/contract_detail.rb +15 -25
- data/{models → lib/models}/ib/execution.rb +1 -1
- data/{models → lib/models}/ib/forex.rb +2 -1
- data/lib/models/ib/future.rb +15 -0
- data/{models → lib/models}/ib/index.rb +3 -2
- data/lib/models/ib/option.rb +78 -0
- data/lib/models/ib/option_detail.rb +55 -0
- data/{models → lib/models}/ib/order.rb +165 -366
- data/{models → lib/models}/ib/order_state.rb +22 -25
- data/lib/models/ib/portfolio_value.rb +64 -0
- data/lib/models/ib/stock.rb +16 -0
- data/{models → lib/models}/ib/underlying.rb +5 -3
- data/lib/models/ib/vertical.rb +96 -0
- data/lib/requires.rb +12 -0
- metadata +64 -188
- data/CLAUDE.md +0 -131
- data/LLM_GUIDE.md +0 -388
- data/bin/simple +0 -91
- data/conditions/ib/execution_condition.rb +0 -31
- data/conditions/ib/margin_condition.rb +0 -28
- data/conditions/ib/order_condition.rb +0 -29
- data/conditions/ib/percent_change_condition.rb +0 -34
- data/conditions/ib/price_condition.rb +0 -44
- data/conditions/ib/time_condition.rb +0 -42
- data/conditions/ib/volume_condition.rb +0 -36
- data/lib/class_extensions.rb +0 -167
- data/lib/ib/contract.rb +0 -30
- data/lib/ib/messages/incoming/abstract_tick.rb +0 -25
- data/lib/ib/messages/incoming/account_message.rb +0 -26
- data/lib/ib/messages/incoming/contract_message.rb +0 -13
- data/lib/ib/messages/incoming/histogram_data.rb +0 -30
- data/lib/ib/messages/incoming/historical_data_update.rb +0 -50
- data/lib/ib/messages/incoming/managed_accounts.rb +0 -21
- data/lib/ib/messages/incoming/market_depth_l2.rb +0 -15
- data/lib/ib/messages/incoming/position_data.rb +0 -21
- data/lib/ib/messages/incoming/positions_multi.rb +0 -15
- data/lib/ib/messages/incoming/receive_fa.rb +0 -30
- data/lib/ib/messages/incoming/tick_by_tick.rb +0 -77
- data/lib/ib/messages/incoming/tick_efp.rb +0 -18
- data/lib/ib/messages/incoming/tick_generic.rb +0 -12
- data/lib/ib/messages/incoming/tick_option.rb +0 -60
- data/lib/ib/messages/incoming/tick_price.rb +0 -60
- data/lib/ib/messages/incoming/tick_size.rb +0 -55
- data/lib/ib/messages/incoming/tick_string.rb +0 -13
- data/lib/ib/messages/outgoing/new-place-order.rb +0 -193
- data/lib/ib/messages/outgoing/old-place-order.rb +0 -147
- data/lib/ib/messages/outgoing/request_historical_data.rb +0 -182
- data/lib/ib/messages/outgoing/request_market_depth.rb +0 -57
- data/lib/ib/messages/outgoing/request_real_time_bars.rb +0 -48
- data/lib/ib/messages/outgoing/request_scanner_subscription.rb +0 -73
- data/lib/ib/messages/outgoing/request_tick_by_tick_data.rb +0 -21
- data/lib/ib/order_condition.rb +0 -26
- data/lib/ib/plugins.rb +0 -27
- data/lib/ib/prepare_data.rb +0 -61
- data/lib/ib/raw_message_parser.rb +0 -99
- data/lib/support/array_function.rb +0 -28
- data/lib/support/logging.rb +0 -45
- data/models/ib/account.rb +0 -72
- data/models/ib/future.rb +0 -64
- data/models/ib/option.rb +0 -149
- data/models/ib/option_detail.rb +0 -84
- data/models/ib/portfolio_value.rb +0 -86
- data/models/ib/spread.rb +0 -176
- data/models/ib/stock.rb +0 -25
- data/plugins/ib/advanced-account.rb +0 -442
- data/plugins/ib/alerts/base-alert.rb +0 -125
- data/plugins/ib/alerts/gateway-alerts.rb +0 -15
- data/plugins/ib/alerts/order-alerts.rb +0 -73
- data/plugins/ib/auto-adjust.rb +0 -0
- data/plugins/ib/connection-tools.rb +0 -122
- data/plugins/ib/eod.rb +0 -326
- data/plugins/ib/greeks.rb +0 -102
- data/plugins/ib/managed-accounts.rb +0 -274
- data/plugins/ib/market-price.rb +0 -150
- data/plugins/ib/option-chain.rb +0 -167
- data/plugins/ib/order-flow.rb +0 -157
- data/plugins/ib/order-prototypes/abstract.rb +0 -67
- data/plugins/ib/order-prototypes/adaptive.rb +0 -40
- data/plugins/ib/order-prototypes/all-in-one.rb +0 -46
- data/plugins/ib/order-prototypes/combo.rb +0 -46
- data/plugins/ib/order-prototypes/forex.rb +0 -40
- data/plugins/ib/order-prototypes/limit.rb +0 -193
- data/plugins/ib/order-prototypes/market.rb +0 -116
- data/plugins/ib/order-prototypes/pegged.rb +0 -169
- data/plugins/ib/order-prototypes/premarket.rb +0 -31
- data/plugins/ib/order-prototypes/stop.rb +0 -202
- data/plugins/ib/order-prototypes/volatility.rb +0 -39
- data/plugins/ib/order-prototypes.rb +0 -118
- data/plugins/ib/probability-of-expiring.rb +0 -109
- data/plugins/ib/process-orders.rb +0 -155
- data/plugins/ib/roll.rb +0 -86
- data/plugins/ib/spread-prototypes/butterfly.rb +0 -77
- data/plugins/ib/spread-prototypes/calendar.rb +0 -97
- data/plugins/ib/spread-prototypes/stock-spread.rb +0 -56
- data/plugins/ib/spread-prototypes/straddle.rb +0 -70
- data/plugins/ib/spread-prototypes/strangle.rb +0 -93
- data/plugins/ib/spread-prototypes/vertical.rb +0 -83
- data/plugins/ib/spread-prototypes.rb +0 -70
- data/plugins/ib/symbols/abstract.rb +0 -136
- data/plugins/ib/symbols/bonds.rb +0 -28
- data/plugins/ib/symbols/cfd.rb +0 -19
- data/plugins/ib/symbols/combo.rb +0 -46
- data/plugins/ib/symbols/commodity.rb +0 -17
- data/plugins/ib/symbols/forex.rb +0 -41
- data/plugins/ib/symbols/futures.rb +0 -127
- data/plugins/ib/symbols/index.rb +0 -43
- data/plugins/ib/symbols/options.rb +0 -99
- data/plugins/ib/symbols/stocks.rb +0 -44
- data/plugins/ib/symbols/version.rb +0 -5
- data/plugins/ib/symbols.rb +0 -118
- data/plugins/ib/verify.rb +0 -226
- data/symbols/w20.yml +0 -210
- data/t.txt +0 -20
- data/update.md +0 -71
|
@@ -10,7 +10,7 @@ subject to the terms and conditions of the IB API Non-Commercial License or the
|
|
|
10
10
|
The known server versions.
|
|
11
11
|
=end
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
known_servers = {
|
|
14
14
|
#min_server_ver_real_time_bars => 34,
|
|
15
15
|
#min_server_ver_scale_orders => 35,
|
|
16
16
|
#min_server_ver_snapshot_mkt_data => 35,
|
|
@@ -19,7 +19,7 @@ KNOWN_SERVERS = {
|
|
|
19
19
|
#min_server_ver_contract_conid => 37,
|
|
20
20
|
:min_server_ver_pta_orders => 39,
|
|
21
21
|
:min_server_ver_fundamental_data => 40,
|
|
22
|
-
:
|
|
22
|
+
:min_server_ver_under_comp => 40,
|
|
23
23
|
:min_server_ver_contract_data_chain => 40,
|
|
24
24
|
:min_server_ver_scale_orders2 => 40,
|
|
25
25
|
:min_server_ver_algo_orders => 41,
|
|
@@ -99,47 +99,16 @@ KNOWN_SERVERS = {
|
|
|
99
99
|
:min_server_ver_order_container => 145, ### > Version Field in Order dropped
|
|
100
100
|
:min_server_ver_smart_depth => 146,
|
|
101
101
|
:min_server_ver_remove_null_all_casting => 147,
|
|
102
|
-
:min_server_ver_d_peg_orders => 148
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
:min_server_ver_encode_msg_ascii7 => 153,
|
|
108
|
-
:min_server_ver_send_all_family_codes => 154,
|
|
109
|
-
:min_server_ver_no_default_open_close => 155,
|
|
110
|
-
:min_server_ver_price_based_volitility => 156,
|
|
111
|
-
:min_server_ver_replace_fa_end => 157,
|
|
112
|
-
:min_server_ver_duration => 158,
|
|
113
|
-
:min_server_ver_market_data_in_shares => 159,
|
|
114
|
-
:min_server_ver_post_to_ats => 160,
|
|
115
|
-
:min_server_ver_wshe_calendar => 161,
|
|
116
|
-
:min_server_ver_auto_cancel_parent => 162,
|
|
117
|
-
:min_server_ver_fractional_size_support => 163,
|
|
118
|
-
:min_server_ver_size_rules => 164,
|
|
119
|
-
:min_server_ver_historical_schedule => 165,
|
|
120
|
-
:min_server_ver_advanced_order_reject => 166,
|
|
121
|
-
:min_server_ver_user_info => 167,
|
|
122
|
-
:min_server_ver_crypto_aggregated_trades => 168,
|
|
123
|
-
:min_server_ver_manual_order_time => 169,
|
|
124
|
-
:min_server_ver_pegbest_pegmid_offsets => 170,
|
|
125
|
-
:min_server_ver_wsh_event_data_filters => 171,
|
|
126
|
-
:min_server_ver_ipo_prices => 172,
|
|
127
|
-
:min_server_ver_wsh_event_data_filters_date => 173,
|
|
128
|
-
:min_server_ver_instrument_timezone => 174,
|
|
129
|
-
:min_server_ver_hmds_market_data_in_shares => 175,
|
|
130
|
-
:min_server_ver_bond_issuerid => 176,
|
|
131
|
-
:min_server_ver_fa_profile_desupport => 177,
|
|
132
|
-
:min_server_ver_pending_price_revision => 178,
|
|
133
|
-
:min_server_ver_fund_data_fields => 179,
|
|
134
|
-
:min_server_ver_manual_order_time_exercise_options => 180,
|
|
135
|
-
:min_server_ver_open_order_ad_strategy => 181,
|
|
136
|
-
:min_server_ver_last_trade_date => 182,
|
|
137
|
-
:min_server_ver_customer_account => 183,
|
|
138
|
-
:min_server_ver_professional_customer => 184
|
|
102
|
+
:min_server_ver_d_peg_orders => 148
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
139
107
|
}
|
|
140
108
|
# 100+ messaging */
|
|
141
109
|
# 100 = enhanced handshake, msg length prefixes
|
|
142
110
|
|
|
143
111
|
MIN_CLIENT_VER = 100
|
|
144
|
-
MAX_CLIENT_VER =
|
|
112
|
+
MAX_CLIENT_VER = 137 #known_servers[:min_server_ver_d_peg_orders]
|
|
113
|
+
|
|
145
114
|
# imessages/outgoing/request_tick_Data is prepared for change to ver. 140 , its commented for now
|
data/lib/ib/socket.rb
CHANGED
|
@@ -1,31 +1,133 @@
|
|
|
1
|
+
require 'socket'
|
|
2
|
+
module IBSupport
|
|
3
|
+
refine Array do
|
|
4
|
+
def tws
|
|
5
|
+
if blank?
|
|
6
|
+
nil.tws
|
|
7
|
+
else
|
|
8
|
+
self.flatten.map( &:tws ).join # [ "", [] , nil].flatten -> ["", nil]
|
|
9
|
+
# elemets with empty array's are cut
|
|
10
|
+
# this is the desired behavior!
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
refine Symbol do
|
|
15
|
+
def tws
|
|
16
|
+
self.to_s.tws
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
refine String do
|
|
20
|
+
def tws
|
|
21
|
+
if empty?
|
|
22
|
+
IB::EOL
|
|
23
|
+
else
|
|
24
|
+
self[-1] == IB::EOL ? self : self+IB::EOL
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
refine Numeric do
|
|
30
|
+
def tws
|
|
31
|
+
self.to_s.tws
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
refine TrueClass do
|
|
36
|
+
def tws
|
|
37
|
+
1.tws
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
refine FalseClass do
|
|
42
|
+
def tws
|
|
43
|
+
0.tws
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
refine NilClass do
|
|
48
|
+
def tws
|
|
49
|
+
IB::EOL
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
1
53
|
module IB
|
|
2
|
-
# includes methods from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
54
|
+
# includes methods from IBSupport
|
|
55
|
+
# which adds a tws-method to
|
|
56
|
+
# - Array
|
|
57
|
+
# - Symbol
|
|
58
|
+
# - String
|
|
59
|
+
# - Numeric
|
|
60
|
+
# - TrueClass, FalseClass and NilClass
|
|
61
|
+
#
|
|
62
|
+
module PrepareData
|
|
63
|
+
using IBSupport
|
|
64
|
+
# First call the method #tws on the data-object
|
|
65
|
+
#
|
|
66
|
+
# Then transfom into an Array using the #Pack-Method
|
|
67
|
+
#
|
|
68
|
+
# The optional Block introduces a user-defined pattern to pack the data.
|
|
69
|
+
#
|
|
70
|
+
# Default is "Na*"
|
|
71
|
+
def prepare_message data
|
|
72
|
+
data = data.tws unless data.is_a?(String) && data[-1]== EOL
|
|
73
|
+
matrize = [data.size,data]
|
|
74
|
+
if block_given? # A user defined decoding-sequence is accepted via block
|
|
75
|
+
matrize.pack yield
|
|
76
|
+
else
|
|
77
|
+
matrize.pack "Na*"
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# The received package is decoded. The parameter (msg) is an Array
|
|
82
|
+
#
|
|
83
|
+
# The protocol is simple: Every Element is treated as Character.
|
|
84
|
+
# Exception: The first Element determines the expected length.
|
|
85
|
+
#
|
|
86
|
+
# The decoded raw-message can further modified by the optional block.
|
|
87
|
+
#
|
|
88
|
+
# The default is to instantiate a Hash: message_id becomes the key.
|
|
89
|
+
# The Hash is returned
|
|
90
|
+
#
|
|
91
|
+
# If a block is provided, no Hash is build and the modified raw-message is returned
|
|
92
|
+
def decode_message msg
|
|
93
|
+
m = Hash.new
|
|
94
|
+
while not msg.blank?
|
|
95
|
+
# the first item is the length
|
|
96
|
+
size= msg[0..4].unpack("N").first
|
|
97
|
+
msg = msg[4..-1]
|
|
98
|
+
# followed by a sequence of characters
|
|
99
|
+
message = msg.unpack("A#{size}").first.split("\0")
|
|
100
|
+
if block_given?
|
|
101
|
+
yield message
|
|
102
|
+
else
|
|
103
|
+
m[message.shift.to_i] = message
|
|
104
|
+
end
|
|
105
|
+
msg = msg[size..-1]
|
|
106
|
+
end
|
|
107
|
+
return m unless block_given?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
class IBSocket < TCPSocket
|
|
113
|
+
include PrepareData
|
|
114
|
+
using IBSupport
|
|
13
115
|
|
|
14
116
|
def initialising_handshake
|
|
15
|
-
v100_prefix = "API".tws.encode 'ascii'
|
|
117
|
+
v100_prefix = "API".tws.encode 'ascii'
|
|
16
118
|
v100_version = self.prepare_message Messages::SERVER_VERSION
|
|
17
119
|
write_data v100_prefix+v100_version
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
120
|
+
## start tws-log
|
|
121
|
+
# [QO] INFO [JTS-SocketListener-49] - State: HEADER, IsAPI: UNKNOWN
|
|
122
|
+
# [QO] INFO [JTS-SocketListener-49] - State: STOP, IsAPI: YES
|
|
123
|
+
# [QO] INFO [JTS-SocketListener-49] - ArEServer: Adding 392382055 with id 2147483647
|
|
124
|
+
# [QO] INFO [JTS-SocketListener-49] - eServersChanged: 1
|
|
125
|
+
# [QO] INFO [JTS-EServerSocket-287] - [2147483647:136:136:1:0:0:0:SYS] Starting new conversation with client on 127.0.0.1
|
|
126
|
+
# [QO] INFO [JTS-EServerSocketNotifier-288] - Starting async queue thread
|
|
127
|
+
# [QO] INFO [JTS-EServerSocket-287] - [2147483647:136:136:1:0:0:0:SYS] Server version is 136
|
|
128
|
+
# [QO] INFO [JTS-EServerSocket-287] - [2147483647:136:136:1:0:0:0:SYS] Client version is 136
|
|
129
|
+
# [QO] INFO [JTS-EServerSocket-287] - [2147483647:136:136:1:0:0:0:SYS] is 3rdParty true
|
|
130
|
+
## end tws-log
|
|
29
131
|
end
|
|
30
132
|
|
|
31
133
|
|
|
@@ -33,9 +135,9 @@ module IB
|
|
|
33
135
|
string = self.gets(EOL)
|
|
34
136
|
|
|
35
137
|
until string
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
138
|
+
# Silently ignores nils
|
|
139
|
+
string = self.gets(EOL)
|
|
140
|
+
sleep 0.1
|
|
39
141
|
end
|
|
40
142
|
|
|
41
143
|
string.chomp
|
|
@@ -52,32 +154,32 @@ module IB
|
|
|
52
154
|
def send_messages *data
|
|
53
155
|
self.syswrite prepare_message(data)
|
|
54
156
|
rescue Errno::ECONNRESET => e
|
|
55
|
-
Connection.logger.
|
|
56
|
-
|
|
57
|
-
|
|
157
|
+
Connection.logger.error{ "Data not accepted by IB \n
|
|
158
|
+
#{data.inspect} \n
|
|
159
|
+
Backtrace:\n "}
|
|
58
160
|
Connection.logger.error e.backtrace
|
|
59
161
|
end
|
|
60
162
|
|
|
61
|
-
def
|
|
163
|
+
def recieve_messages
|
|
62
164
|
begin
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
165
|
+
complete_message_buffer = []
|
|
166
|
+
begin
|
|
167
|
+
# this is the blocking version of recv
|
|
168
|
+
buffer = self.recvfrom(4096)[0]
|
|
169
|
+
# STDOUT.puts "BUFFER:: #{buffer.inspect}"
|
|
170
|
+
complete_message_buffer << buffer
|
|
171
|
+
|
|
172
|
+
end while buffer.size == 4096
|
|
173
|
+
complete_message_buffer.join('')
|
|
72
174
|
rescue Errno::ECONNRESET => e
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
175
|
+
Connection.logger.error{ "Data Buffer is not filling \n
|
|
176
|
+
The Buffer: #{buffer.inspect} \n
|
|
177
|
+
Backtrace:\n
|
|
178
|
+
#{e.backtrace.join("\n") } " }
|
|
179
|
+
Kernel.exit
|
|
78
180
|
end
|
|
79
181
|
end
|
|
80
182
|
|
|
81
|
-
end # class
|
|
183
|
+
end # class IBSocket
|
|
82
184
|
|
|
83
185
|
end # module IB
|
data/lib/ib/support.rb
CHANGED
|
@@ -1,242 +1,160 @@
|
|
|
1
|
-
# Class-extensions only applied when data are read from the tws
|
|
2
|
-
# Array : read several formats
|
|
3
|
-
# Array, String, Symbol, true, false, nil : apply tws.method
|
|
4
|
-
#
|
|
5
|
-
# Apply through: module aaxx
|
|
6
|
-
# using IB::Support
|
|
7
|
-
#
|
|
8
|
-
module IB
|
|
9
|
-
module Support
|
|
10
|
-
|
|
11
|
-
refine Array do
|
|
12
|
-
|
|
13
|
-
def zero?
|
|
14
|
-
false
|
|
15
|
-
end
|
|
16
|
-
# Returns the integer.
|
|
17
|
-
# retuns nil otherwise or if no element is left on the stack
|
|
18
|
-
def read_int
|
|
19
|
-
i= self.shift rescue nil
|
|
20
|
-
i = i.to_i unless i.blank? # this includes conversion of string to zero(0)
|
|
21
|
-
i.is_a?( Integer ) && i != 2147483647 ? i : nil
|
|
22
|
-
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def read_float
|
|
26
|
-
i= self.shift rescue nil
|
|
27
|
-
i = i.to_f unless i.blank?
|
|
28
|
-
|
|
29
|
-
end
|
|
30
|
-
def read_decimal
|
|
31
|
-
i = self.shift rescue nil
|
|
32
|
-
return nil if i.blank?
|
|
33
|
-
d = i.to_d
|
|
34
|
-
return nil unless d.is_a?(Numeric) && d < IB::TWS_MAX
|
|
35
|
-
if d == d.to_i
|
|
36
|
-
d.to_i
|
|
37
|
-
else
|
|
38
|
-
d.to_f
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
alias read_decimal_max read_decimal
|
|
43
|
-
|
|
44
|
-
## Values -1 and below indicate: Not computed (TickOptionComputation)
|
|
45
|
-
def read_decimal_limit_1
|
|
46
|
-
i= read_decimal
|
|
47
|
-
i <= -1 ? nil : i
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
## Values -2 and below indicate: Not computed (TickOptionComputation)
|
|
51
|
-
def read_decimal_limit_2
|
|
52
|
-
i= read_decimal
|
|
53
|
-
i <= -2 ? nil : i
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def read_string
|
|
58
|
-
self.shift rescue ""
|
|
59
|
-
end
|
|
60
|
-
## reads a string and checks if NULL == IB::TWS_MAX is present.
|
|
61
|
-
## in that case: returns nil. otherwise: returns the string
|
|
62
|
-
def read_string_not_null
|
|
63
|
-
r = read_string
|
|
64
|
-
rd = r.to_d unless r.blank?
|
|
65
|
-
rd.is_a?(Numeric) && rd >= IB::TWS_MAX ? nil : r
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def read_symbol
|
|
69
|
-
read_string.to_sym
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
# convert xml into a hash
|
|
73
|
-
def read_xml
|
|
74
|
-
Ox.load( read_string(), mode: :hash_no_attrs)
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def read_int_date
|
|
79
|
-
t= read_int
|
|
80
|
-
s= Time.at(t.to_i)
|
|
81
|
-
# s.year == 1970 --> data is most likely a date-string
|
|
82
|
-
s.year == 1970 ? Date.parse(t.to_s) : s
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def read_parse_date
|
|
86
|
-
Time.parse read_string
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def read_boolean
|
|
90
|
-
|
|
91
|
-
v = self.shift rescue nil
|
|
92
|
-
case v
|
|
93
|
-
when "1"
|
|
94
|
-
true
|
|
95
|
-
when "0"
|
|
96
|
-
false
|
|
97
|
-
else nil
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def read_datetime
|
|
103
|
-
the_string = read_string
|
|
104
|
-
the_string.blank? ? nil : DateTime.parse(the_string)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def read_date
|
|
108
|
-
the_string = read_string
|
|
109
|
-
the_string.blank? ? nil : Date.parse(the_string)
|
|
110
|
-
end
|
|
111
|
-
# def read_array
|
|
112
|
-
# count = read_int
|
|
113
|
-
# end
|
|
114
|
-
|
|
115
|
-
## originally provided in socket.rb
|
|
116
|
-
# # Returns loaded Array or [] if count was 0#
|
|
117
|
-
#
|
|
118
|
-
# Without providing a Block, the elements are treated as string
|
|
119
|
-
def read_array hashmode:false, &block
|
|
120
|
-
count = read_int
|
|
121
|
-
case count
|
|
122
|
-
when 0
|
|
123
|
-
[]
|
|
124
|
-
when nil
|
|
125
|
-
nil
|
|
126
|
-
else
|
|
127
|
-
count= count + count if hashmode
|
|
128
|
-
if block_given?
|
|
129
|
-
Array.new(count, &block)
|
|
130
|
-
else
|
|
131
|
-
Array.new( count ){ read_string }
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
#
|
|
136
|
-
# Returns a hash
|
|
137
|
-
# Expected Buffer-Format:
|
|
138
|
-
# count (of Hash-elements)
|
|
139
|
-
# count* key|Value
|
|
140
|
-
# Key's are transformed to symbols, values are treated as string
|
|
141
|
-
def read_hash
|
|
142
|
-
tags = read_array( hashmode: true ) # { |_| [read_string, read_string] }
|
|
143
|
-
result = if tags.nil? || tags.flatten.empty?
|
|
144
|
-
tags # {}
|
|
145
|
-
else
|
|
146
|
-
interim = if tags.size.modulo(2).zero?
|
|
147
|
-
Hash[*tags.flatten]
|
|
148
|
-
else
|
|
149
|
-
Hash[*tags[0..-2].flatten] # omit the last element
|
|
150
|
-
end
|
|
151
|
-
# symbolize Hash
|
|
152
|
-
interim.map { |k, v| [k.to_sym, v] unless k.nil? }.compact.to_h
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
#
|
|
156
|
-
|
|
157
|
-
def read_contract # read a standard contract and return als hash
|
|
158
|
-
{ con_id: read_int,
|
|
159
|
-
symbol: read_string,
|
|
160
|
-
sec_type: read_string,
|
|
161
|
-
expiry: read_string,
|
|
162
|
-
strike: read_decimal,
|
|
163
|
-
right: read_string,
|
|
164
|
-
multiplier: read_decimal,
|
|
165
|
-
exchange: read_string,
|
|
166
|
-
currency: read_string,
|
|
167
|
-
local_symbol: read_string,
|
|
168
|
-
trading_class: read_string }
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
def read_bar # read a Historical data bar
|
|
173
|
-
# ** historicalDataUpdate: time open close high low ** covered here
|
|
174
|
-
# historicalData time open high low close <- covered in messages/incomming
|
|
175
|
-
{ :time => read_int_date, # conversion of epoche-time-integer to Dateime
|
|
176
|
-
# requires format_date in request to be "2"
|
|
177
|
-
# (outgoing/bar_requests # RequestHistoricalData#Encoding)
|
|
178
|
-
:open => read_decimal,
|
|
179
|
-
:close => read_decimal,
|
|
180
|
-
:high => read_decimal,
|
|
181
|
-
:low => read_decimal,
|
|
182
|
-
:wap => read_decimal,
|
|
183
|
-
:volume => read_int,
|
|
184
|
-
# :has_gaps => read_string, # only in ServerVersion < 124
|
|
185
|
-
:trades => read_int }
|
|
186
|
-
|
|
187
|
-
end
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
alias read_bool read_boolean
|
|
191
|
-
|
|
192
|
-
def tws
|
|
193
|
-
if blank?
|
|
194
|
-
nil.tws
|
|
195
|
-
else
|
|
196
|
-
self.flatten.map( &:tws ).join # [ "", [] , nil].flatten -> ["", nil]
|
|
197
|
-
# elements with empty array's are cut
|
|
198
|
-
# this is the desired behavior!
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end # refining array
|
|
202
|
-
refine Symbol do
|
|
203
|
-
def tws
|
|
204
|
-
self.to_s.tws
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
refine String do
|
|
208
|
-
def tws
|
|
209
|
-
if empty?
|
|
210
|
-
IB::EOL
|
|
211
|
-
else
|
|
212
|
-
self[-1] == IB::EOL ? self : self+IB::EOL
|
|
213
|
-
end
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
refine Numeric do
|
|
218
|
-
def tws
|
|
219
|
-
self.to_s.tws
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
refine TrueClass do
|
|
224
|
-
def tws
|
|
225
|
-
1.tws
|
|
226
|
-
end
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
refine FalseClass do
|
|
230
|
-
def tws
|
|
231
|
-
0.tws
|
|
232
|
-
end
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
refine NilClass do
|
|
236
|
-
def tws
|
|
237
|
-
IB::EOL
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
end
|
|
241
1
|
|
|
2
|
+
module IBSupport
|
|
3
|
+
refine Array do
|
|
4
|
+
|
|
5
|
+
def zero?
|
|
6
|
+
false
|
|
7
|
+
end
|
|
8
|
+
# Returns the integer.
|
|
9
|
+
# retuns nil otherwise or if no element is left on the stack
|
|
10
|
+
def read_int
|
|
11
|
+
i= self.shift rescue nil
|
|
12
|
+
i = i.to_i unless i.blank? # this includes conversion of string to zero(0)
|
|
13
|
+
i.is_a?( Integer ) ? i : nil
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def read_float
|
|
17
|
+
i= self.shift rescue nil
|
|
18
|
+
i = i.to_f unless i.blank?
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
def read_decimal
|
|
22
|
+
i= self.shift rescue nil
|
|
23
|
+
i = i.to_d unless i.blank?
|
|
24
|
+
i.is_a?(Numeric) && i < IB::TWS_MAX ? i : nil # return nil, if a very large number is transmitted
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
alias read_decimal_max read_decimal
|
|
28
|
+
|
|
29
|
+
## Values -1 and below indicate: Not computed (TickOptionComputation)
|
|
30
|
+
def read_decimal_limit_1
|
|
31
|
+
i= read_decimal
|
|
32
|
+
i <= -1 ? nil : i
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
## Values -2 and below indicate: Not computed (TickOptionComputation)
|
|
36
|
+
def read_decimal_limit_2
|
|
37
|
+
i= read_decimal
|
|
38
|
+
i <= -2 ? nil : i
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def read_string
|
|
43
|
+
self.shift rescue ""
|
|
44
|
+
end
|
|
45
|
+
## reads a string and proofs if NULL == IB::TWS_MAX is present.
|
|
46
|
+
## in that case: returns nil. otherwise: returns the string
|
|
47
|
+
def read_string_not_null
|
|
48
|
+
r = read_string
|
|
49
|
+
rd = r.to_d unless r.blank?
|
|
50
|
+
rd.is_a?(Numeric) && rd >= IB::TWS_MAX ? nil : r
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def read_symbol
|
|
54
|
+
read_string.to_sym
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# convert xml into a hash
|
|
58
|
+
def read_xml
|
|
59
|
+
Ox.load( read_string(), mode: :hash_no_attrs)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def read_int_date
|
|
64
|
+
t= read_int
|
|
65
|
+
s= Time.at(t)
|
|
66
|
+
# s.year == 1970 --> data is most likely a date-string
|
|
67
|
+
s.year == 1970 ? Date.parse(t.to_s) : s
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def read_parse_date
|
|
71
|
+
Time.parse read_string
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def read_boolean
|
|
75
|
+
|
|
76
|
+
v = self.shift rescue nil
|
|
77
|
+
case v
|
|
78
|
+
when "1"
|
|
79
|
+
true
|
|
80
|
+
when "0"
|
|
81
|
+
false
|
|
82
|
+
else nil
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def read_datetime
|
|
88
|
+
the_string = read_string
|
|
89
|
+
the_string.blank? ? nil : DateTime.parse(the_string)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def read_date
|
|
93
|
+
the_string = read_string
|
|
94
|
+
the_string.blank? ? nil : Date.parse(the_string)
|
|
95
|
+
end
|
|
96
|
+
# def read_array
|
|
97
|
+
# count = read_int
|
|
98
|
+
# end
|
|
99
|
+
|
|
100
|
+
## originally provided in socket.rb
|
|
101
|
+
# # Returns loaded Array or [] if count was 0#
|
|
102
|
+
#
|
|
103
|
+
# Without providing a Block, the elements are treated as string
|
|
104
|
+
def read_array hashmode:false, &block
|
|
105
|
+
count = read_int
|
|
106
|
+
case count
|
|
107
|
+
when 0
|
|
108
|
+
[]
|
|
109
|
+
when nil
|
|
110
|
+
nil
|
|
111
|
+
else
|
|
112
|
+
count= count + count if hashmode
|
|
113
|
+
if block_given?
|
|
114
|
+
Array.new(count, &block)
|
|
115
|
+
else
|
|
116
|
+
Array.new( count ){ read_string }
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
#
|
|
121
|
+
# Returns a hash
|
|
122
|
+
# Expected Buffer-Format:
|
|
123
|
+
# count (of Hash-elements)
|
|
124
|
+
# count* key|Value
|
|
125
|
+
# Key's are transformed to symbols, values are treated as string
|
|
126
|
+
def read_hash
|
|
127
|
+
tags = read_array( hashmode: true ) # { |_| [read_string, read_string] }
|
|
128
|
+
result = if tags.nil? || tags.flatten.empty?
|
|
129
|
+
tags
|
|
130
|
+
else
|
|
131
|
+
interim = if tags.size.modulo(2).zero?
|
|
132
|
+
Hash[*tags.flatten]
|
|
133
|
+
else
|
|
134
|
+
Hash[*tags[0..-2].flatten] # omit the last element
|
|
135
|
+
end
|
|
136
|
+
# symbolize Hash
|
|
137
|
+
Hash[interim.map { |k, v| [k.to_sym, v] unless k.nil? }.compact]
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
#
|
|
141
|
+
|
|
142
|
+
def read_contract # read a standard contract and return als hash
|
|
143
|
+
{ con_id: read_int,
|
|
144
|
+
symbol: read_string,
|
|
145
|
+
sec_type: read_string,
|
|
146
|
+
expiry: read_string,
|
|
147
|
+
strike: read_decimal,
|
|
148
|
+
right: read_string,
|
|
149
|
+
multiplier: read_int,
|
|
150
|
+
exchange: read_string,
|
|
151
|
+
currency: read_string,
|
|
152
|
+
local_symbol: read_string,
|
|
153
|
+
trading_class: read_string } # new Version 8
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
alias read_bool read_boolean
|
|
159
|
+
end
|
|
242
160
|
end
|
data/lib/ib/version.rb
CHANGED