ib-api 10.33.1
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 +7 -0
- data/.gitignore +52 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/CLAUDE.md +131 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +120 -0
- data/Guardfile +24 -0
- data/LICENSE +674 -0
- data/LLM_GUIDE.md +388 -0
- data/README.md +114 -0
- data/Rakefile +11 -0
- data/VERSION +1 -0
- data/api.gemspec +50 -0
- data/bin/console +96 -0
- data/bin/console.yml +3 -0
- data/bin/setup +8 -0
- data/bin/simple +91 -0
- data/changelog.md +32 -0
- data/conditions/ib/execution_condition.rb +31 -0
- data/conditions/ib/margin_condition.rb +28 -0
- data/conditions/ib/order_condition.rb +29 -0
- data/conditions/ib/percent_change_condition.rb +34 -0
- data/conditions/ib/price_condition.rb +44 -0
- data/conditions/ib/time_condition.rb +42 -0
- data/conditions/ib/volume_condition.rb +36 -0
- data/lib/class_extensions.rb +167 -0
- data/lib/ib/base.rb +109 -0
- data/lib/ib/base_properties.rb +178 -0
- data/lib/ib/connection.rb +573 -0
- data/lib/ib/constants.rb +402 -0
- data/lib/ib/contract.rb +30 -0
- data/lib/ib/errors.rb +52 -0
- data/lib/ib/messages/abstract_message.rb +68 -0
- data/lib/ib/messages/incoming/abstract_message.rb +116 -0
- data/lib/ib/messages/incoming/abstract_tick.rb +25 -0
- data/lib/ib/messages/incoming/account_message.rb +26 -0
- data/lib/ib/messages/incoming/alert.rb +34 -0
- data/lib/ib/messages/incoming/contract_data.rb +105 -0
- data/lib/ib/messages/incoming/contract_message.rb +13 -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/histogram_data.rb +30 -0
- data/lib/ib/messages/incoming/historical_data.rb +65 -0
- data/lib/ib/messages/incoming/historical_data_update.rb +50 -0
- data/lib/ib/messages/incoming/managed_accounts.rb +21 -0
- data/lib/ib/messages/incoming/market_depth.rb +34 -0
- data/lib/ib/messages/incoming/market_depth_l2.rb +15 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +19 -0
- data/lib/ib/messages/incoming/open_order.rb +290 -0
- data/lib/ib/messages/incoming/order_status.rb +85 -0
- data/lib/ib/messages/incoming/portfolio_value.rb +47 -0
- data/lib/ib/messages/incoming/position_data.rb +21 -0
- data/lib/ib/messages/incoming/positions_multi.rb +15 -0
- data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib/messages/incoming/receive_fa.rb +30 -0
- data/lib/ib/messages/incoming/scanner_data.rb +54 -0
- data/lib/ib/messages/incoming/tick_by_tick.rb +77 -0
- data/lib/ib/messages/incoming/tick_efp.rb +18 -0
- data/lib/ib/messages/incoming/tick_generic.rb +12 -0
- data/lib/ib/messages/incoming/tick_option.rb +60 -0
- data/lib/ib/messages/incoming/tick_price.rb +60 -0
- data/lib/ib/messages/incoming/tick_size.rb +55 -0
- data/lib/ib/messages/incoming/tick_string.rb +13 -0
- data/lib/ib/messages/incoming.rb +292 -0
- data/lib/ib/messages/outgoing/abstract_message.rb +84 -0
- data/lib/ib/messages/outgoing/bar_request_message.rb +247 -0
- data/lib/ib/messages/outgoing/new-place-order.rb +193 -0
- data/lib/ib/messages/outgoing/old-place-order.rb +147 -0
- data/lib/ib/messages/outgoing/place_order.rb +149 -0
- data/lib/ib/messages/outgoing/request_account_summary.rb +79 -0
- data/lib/ib/messages/outgoing/request_historical_data.rb +182 -0
- data/lib/ib/messages/outgoing/request_market_data.rb +102 -0
- data/lib/ib/messages/outgoing/request_market_depth.rb +57 -0
- data/lib/ib/messages/outgoing/request_real_time_bars.rb +48 -0
- data/lib/ib/messages/outgoing/request_scanner_subscription.rb +73 -0
- data/lib/ib/messages/outgoing/request_tick_by_tick_data.rb +21 -0
- data/lib/ib/messages/outgoing.rb +410 -0
- data/lib/ib/messages.rb +139 -0
- data/lib/ib/order_condition.rb +26 -0
- data/lib/ib/plugins.rb +27 -0
- data/lib/ib/prepare_data.rb +61 -0
- data/lib/ib/raw_message_parser.rb +99 -0
- data/lib/ib/socket.rb +83 -0
- data/lib/ib/support.rb +236 -0
- data/lib/ib/version.rb +6 -0
- data/lib/ib-api.rb +44 -0
- data/lib/server_versions.rb +145 -0
- data/lib/support/array_function.rb +28 -0
- data/lib/support/logging.rb +45 -0
- data/models/ib/account.rb +72 -0
- data/models/ib/account_value.rb +33 -0
- data/models/ib/bag.rb +55 -0
- data/models/ib/bar.rb +31 -0
- data/models/ib/combo_leg.rb +127 -0
- data/models/ib/contract.rb +411 -0
- data/models/ib/contract_detail.rb +118 -0
- data/models/ib/execution.rb +67 -0
- data/models/ib/forex.rb +12 -0
- data/models/ib/future.rb +64 -0
- data/models/ib/index.rb +14 -0
- data/models/ib/option.rb +149 -0
- data/models/ib/option_detail.rb +84 -0
- data/models/ib/order.rb +720 -0
- data/models/ib/order_state.rb +155 -0
- data/models/ib/portfolio_value.rb +86 -0
- data/models/ib/spread.rb +176 -0
- data/models/ib/stock.rb +25 -0
- data/models/ib/underlying.rb +32 -0
- data/plugins/ib/advanced-account.rb +442 -0
- data/plugins/ib/alerts/base-alert.rb +125 -0
- data/plugins/ib/alerts/gateway-alerts.rb +15 -0
- data/plugins/ib/alerts/order-alerts.rb +73 -0
- data/plugins/ib/auto-adjust.rb +0 -0
- data/plugins/ib/connection-tools.rb +122 -0
- data/plugins/ib/eod.rb +326 -0
- data/plugins/ib/greeks.rb +102 -0
- data/plugins/ib/managed-accounts.rb +274 -0
- data/plugins/ib/market-price.rb +150 -0
- data/plugins/ib/option-chain.rb +167 -0
- data/plugins/ib/order-flow.rb +157 -0
- data/plugins/ib/order-prototypes/abstract.rb +67 -0
- data/plugins/ib/order-prototypes/adaptive.rb +40 -0
- data/plugins/ib/order-prototypes/all-in-one.rb +46 -0
- data/plugins/ib/order-prototypes/combo.rb +46 -0
- data/plugins/ib/order-prototypes/forex.rb +40 -0
- data/plugins/ib/order-prototypes/limit.rb +193 -0
- data/plugins/ib/order-prototypes/market.rb +116 -0
- data/plugins/ib/order-prototypes/pegged.rb +169 -0
- data/plugins/ib/order-prototypes/premarket.rb +31 -0
- data/plugins/ib/order-prototypes/stop.rb +202 -0
- data/plugins/ib/order-prototypes/volatility.rb +39 -0
- data/plugins/ib/order-prototypes.rb +118 -0
- data/plugins/ib/probability-of-expiring.rb +109 -0
- data/plugins/ib/process-orders.rb +155 -0
- data/plugins/ib/roll.rb +86 -0
- data/plugins/ib/spread-prototypes/butterfly.rb +77 -0
- data/plugins/ib/spread-prototypes/calendar.rb +97 -0
- data/plugins/ib/spread-prototypes/stock-spread.rb +56 -0
- data/plugins/ib/spread-prototypes/straddle.rb +70 -0
- data/plugins/ib/spread-prototypes/strangle.rb +93 -0
- data/plugins/ib/spread-prototypes/vertical.rb +83 -0
- data/plugins/ib/spread-prototypes.rb +70 -0
- data/plugins/ib/symbols/abstract.rb +136 -0
- data/plugins/ib/symbols/bonds.rb +28 -0
- data/plugins/ib/symbols/cfd.rb +19 -0
- data/plugins/ib/symbols/combo.rb +46 -0
- data/plugins/ib/symbols/commodity.rb +17 -0
- data/plugins/ib/symbols/forex.rb +41 -0
- data/plugins/ib/symbols/futures.rb +127 -0
- data/plugins/ib/symbols/index.rb +43 -0
- data/plugins/ib/symbols/options.rb +99 -0
- data/plugins/ib/symbols/stocks.rb +44 -0
- data/plugins/ib/symbols/version.rb +5 -0
- data/plugins/ib/symbols.rb +118 -0
- data/plugins/ib/verify.rb +226 -0
- data/symbols/w20.yml +210 -0
- data/t.txt +20 -0
- data/update.md +71 -0
- metadata +327 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
module Messages
|
|
3
|
+
module Incoming
|
|
4
|
+
extend Messages # def_message macros
|
|
5
|
+
|
|
6
|
+
# This message is received when the market in an option or its underlier moves.
|
|
7
|
+
# TWS option model volatilities, prices, and deltas, along with the present
|
|
8
|
+
# value of dividends expected on that options underlier are received.
|
|
9
|
+
# TickOption message contains following @data:
|
|
10
|
+
# :ticker_id - Id that was specified previously in the call to reqMktData()
|
|
11
|
+
# :tick_type - Specifies the type of option computation (see TICK_TYPES).
|
|
12
|
+
# :implied_volatility - The implied volatility calculated by the TWS option
|
|
13
|
+
# modeler, using the specified :tick_type value.
|
|
14
|
+
# :delta - The option delta value.
|
|
15
|
+
# :option_price - The option price.
|
|
16
|
+
# :pv_dividend - The present value of dividends expected on the options underlier
|
|
17
|
+
# :gamma - The option gamma value.
|
|
18
|
+
# :vega - The option vega value.
|
|
19
|
+
# :theta - The option theta value.
|
|
20
|
+
# :under_price - The price of the underlying.
|
|
21
|
+
TickOption = TickOptionComputation =
|
|
22
|
+
def_message([21, 0], AbstractTick,
|
|
23
|
+
[:ticker_id, :int],
|
|
24
|
+
[:tick_type, :int],
|
|
25
|
+
[:tick_attribute, :int],
|
|
26
|
+
[:implied_volatility, :decimal_limit_1], # -1 and below
|
|
27
|
+
[:delta, :decimal_limit_2], # -2 and below
|
|
28
|
+
[:option_price, :decimal_limit_1], # -1 -"-
|
|
29
|
+
[:pv_dividend, :decimal_limit_1], # -1 -"-
|
|
30
|
+
[:gamma, :decimal_limit_2], # -2 -"-
|
|
31
|
+
[:vega, :decimal_limit_2], # -2 -"-
|
|
32
|
+
[:theta, :decimal_limit_2], # -2 -"-
|
|
33
|
+
[:under_price, :decimal_limit_1]) do
|
|
34
|
+
|
|
35
|
+
"<TickOption #{type} " +
|
|
36
|
+
"option @ #{"%8.3f" % (option_price || -1)}, IV: #{"%4.3f" % (implied_volatility || -1)}, " +
|
|
37
|
+
"delta: #{"%5.3f" % (delta || -1)}, " +
|
|
38
|
+
"gamma: #{"%6.4f" % (gamma || -1)}, vega: #{ "%6.5f" % (vega || -1)}, " +
|
|
39
|
+
"theta: #{"%7.6f" % (theta || -1)}, pv_dividend: #{"%5.3f" % (pv_dividend || -1)}, " +
|
|
40
|
+
"underlying @ #{"% 8.3f" % (under_price || -1)} >"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class TickOption
|
|
44
|
+
def greeks
|
|
45
|
+
{ delta: delta, gamma: gamma, vega: vega, theta: theta }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def iv
|
|
49
|
+
implied_volatility
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def greeks?
|
|
54
|
+
greeks.values.any? &:present?
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
module Messages
|
|
3
|
+
module Incoming
|
|
4
|
+
extend Messages # def_message macros
|
|
5
|
+
|
|
6
|
+
# The IB code seems to dispatch up to two wrapped objects for this message, a tickPrice
|
|
7
|
+
# and sometimes a tickSize, which seems to be identical to the TICK_SIZE object.
|
|
8
|
+
#
|
|
9
|
+
# Important note from
|
|
10
|
+
# http://chuckcaplan.com/twsapi/index.php/void%20tickPrice%28%29 :
|
|
11
|
+
#
|
|
12
|
+
# "The low you get is NOT the low for the day as you'd expect it
|
|
13
|
+
# to be. It appears IB calculates the low based on all
|
|
14
|
+
# transactions after 4pm the previous day. The most inaccurate
|
|
15
|
+
# results occur when the stock moves up in the 4-6pm aftermarket
|
|
16
|
+
# on the previous day and then gaps open upward in the
|
|
17
|
+
# morning. The low you receive from TWS can be easily be several
|
|
18
|
+
# points different from the actual 9:30am-4pm low for the day in
|
|
19
|
+
# cases like this. If you require a correct traded low for the
|
|
20
|
+
# day, you can't get it from the TWS API. One possible source to
|
|
21
|
+
# help build the right data would be to compare against what Yahoo
|
|
22
|
+
# lists on finance.yahoo.com/q?s=ticker under the "Day's Range"
|
|
23
|
+
# statistics (be careful here, because Yahoo will use anti-Denial
|
|
24
|
+
# of Service techniques to hang your connection if you try to
|
|
25
|
+
# request too many bytes in a short period of time from them). For
|
|
26
|
+
# most purposes, a good enough approach would start by replacing
|
|
27
|
+
# the TWS low for the day with Yahoo's day low when you first
|
|
28
|
+
# start watching a stock ticker; let's call this time T. Then,
|
|
29
|
+
# update your internal low if the bid or ask tick you receive is
|
|
30
|
+
# lower than that for the remainder of the day. You should check
|
|
31
|
+
# against Yahoo again at time T+20min to handle the occasional
|
|
32
|
+
# case where the stock set a new low for the day in between
|
|
33
|
+
# T-20min (the real time your original quote was from, taking into
|
|
34
|
+
# account the delay) and time T. After that you should have a
|
|
35
|
+
# correct enough low for the rest of the day as long as you keep
|
|
36
|
+
# updating based on the bid/ask. It could still get slightly off
|
|
37
|
+
# in a case where a short transaction setting a new low appears in
|
|
38
|
+
# between ticks of data that TWS sends you. The high is probably
|
|
39
|
+
# distorted in the same way the low is, which would throw your
|
|
40
|
+
# results off if the stock traded after-hours and gapped down. It
|
|
41
|
+
# should be corrected in a similar way as described above if this
|
|
42
|
+
# is important to you."
|
|
43
|
+
#
|
|
44
|
+
# IB then emits at most 2 events on eWrapper:
|
|
45
|
+
# tickPrice( tickerId, tickType, price, canAutoExecute)
|
|
46
|
+
# tickSize( tickerId, sizeTickType, size)
|
|
47
|
+
TickPrice = def_message [1, 6], AbstractTick,
|
|
48
|
+
[:ticker_id, :int],
|
|
49
|
+
[:tick_type, :int],
|
|
50
|
+
[:price, :decimal],
|
|
51
|
+
[:size, :int],
|
|
52
|
+
[:can_auto_execute, :int]
|
|
53
|
+
class TickPrice
|
|
54
|
+
def valid?
|
|
55
|
+
super && !price.zero?
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
module Messages
|
|
3
|
+
module Incoming
|
|
4
|
+
extend Messages # def_message macros
|
|
5
|
+
|
|
6
|
+
# The IB code seems to dispatch up to two wrapped objects for this message, a tickPrice
|
|
7
|
+
# and sometimes a tickSize, which seems to be identical to the TICK_SIZE object.
|
|
8
|
+
#
|
|
9
|
+
# Important note from
|
|
10
|
+
# http://chuckcaplan.com/twsapi/index.php/void%20tickPrice%28%29 :
|
|
11
|
+
#
|
|
12
|
+
# "The low you get is NOT the low for the day as you'd expect it
|
|
13
|
+
# to be. It appears IB calculates the low based on all
|
|
14
|
+
# transactions after 4pm the previous day. The most inaccurate
|
|
15
|
+
# results occur when the stock moves up in the 4-6pm aftermarket
|
|
16
|
+
# on the previous day and then gaps open upward in the
|
|
17
|
+
# morning. The low you receive from TWS can be easily be several
|
|
18
|
+
# points different from the actual 9:30am-4pm low for the day in
|
|
19
|
+
# cases like this. If you require a correct traded low for the
|
|
20
|
+
# day, you can't get it from the TWS API. One possible source to
|
|
21
|
+
# help build the right data would be to compare against what Yahoo
|
|
22
|
+
# lists on finance.yahoo.com/q?s=ticker under the "Day's Range"
|
|
23
|
+
# statistics (be careful here, because Yahoo will use anti-Denial
|
|
24
|
+
# of Service techniques to hang your connection if you try to
|
|
25
|
+
# request too many bytes in a short period of time from them). For
|
|
26
|
+
# most purposes, a good enough approach would start by replacing
|
|
27
|
+
# the TWS low for the day with Yahoo's day low when you first
|
|
28
|
+
# start watching a stock ticker; let's call this time T. Then,
|
|
29
|
+
# update your internal low if the bid or ask tick you receive is
|
|
30
|
+
# lower than that for the remainder of the day. You should check
|
|
31
|
+
# against Yahoo again at time T+20min to handle the occasional
|
|
32
|
+
# case where the stock set a new low for the day in between
|
|
33
|
+
# T-20min (the real time your original quote was from, taking into
|
|
34
|
+
# account the delay) and time T. After that you should have a
|
|
35
|
+
# correct enough low for the rest of the day as long as you keep
|
|
36
|
+
# updating based on the bid/ask. It could still get slightly off
|
|
37
|
+
# in a case where a short transaction setting a new low appears in
|
|
38
|
+
# between ticks of data that TWS sends you. The high is probably
|
|
39
|
+
# distorted in the same way the low is, which would throw your
|
|
40
|
+
# results off if the stock traded after-hours and gapped down. It
|
|
41
|
+
# should be corrected in a similar way as described above if this
|
|
42
|
+
# is important to you."
|
|
43
|
+
#
|
|
44
|
+
# IB then emits at most 2 events on eWrapper:
|
|
45
|
+
# tickPrice( tickerId, tickType, price, canAutoExecute)
|
|
46
|
+
# tickSize( tickerId, sizeTickType, size)
|
|
47
|
+
|
|
48
|
+
TickSize = def_message [2, 6], AbstractTick,
|
|
49
|
+
[:ticker_id, :int],
|
|
50
|
+
[:tick_type, :int],
|
|
51
|
+
[:size, :int]
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
#require 'ib/messages/incoming/abstract_message'
|
|
2
|
+
|
|
3
|
+
# EClientSocket.java uses sendMax() rather than send() for a number of these.
|
|
4
|
+
# It sends an EOL rather than a number if the value == Integer.MAX_VALUE (or Double.MAX_VALUE).
|
|
5
|
+
# These fields are initialized to this MAX_VALUE.
|
|
6
|
+
# This has been implemented with nils in Ruby to represent the case where an EOL should be sent.
|
|
7
|
+
|
|
8
|
+
# TODO: Don't instantiate messages, use their classes as just namespace for .encode/decode
|
|
9
|
+
# TODO: realize Message#fire method that raises EWrapper events
|
|
10
|
+
|
|
11
|
+
module IB
|
|
12
|
+
module Messages
|
|
13
|
+
|
|
14
|
+
# Incoming IB messages (received from TWS/Gateway)
|
|
15
|
+
module Incoming
|
|
16
|
+
extend Messages # def_message macros
|
|
17
|
+
|
|
18
|
+
### Define short message classes in-line:
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
NewsBulletins =
|
|
22
|
+
def_message 14, [:request_id, :int], # unique incrementing bulletin ID.
|
|
23
|
+
[:type, :int], # Type of bulletin. Valid values include:
|
|
24
|
+
# 1 = Regular news bulletin
|
|
25
|
+
# 2 = Exchange no longer available for trading
|
|
26
|
+
# 3 = Exchange is available for trading
|
|
27
|
+
[:text, :string], # The bulletin's message text.
|
|
28
|
+
[:exchange, :string] # Exchange from which this message originated.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Receives an converted XML document that describes the valid parameters that a scanner
|
|
32
|
+
# subscription can have (for outgoing RequestScannerSubscription message).
|
|
33
|
+
ScannerParameters = def_message 19, [:xml, :xml]
|
|
34
|
+
|
|
35
|
+
class ScannerParameters
|
|
36
|
+
# returns a List of Hashes specifing Instruments.
|
|
37
|
+
# > C.received[:ScannerParameters].first.instruments.first
|
|
38
|
+
# => {:name=>"US Stocks",
|
|
39
|
+
# :type=>"STK",
|
|
40
|
+
# :filters=>"AFTERHRSCHANGEPERC,AVGOPTVOLUME,AVGPRICETARGET,AVGRATING,AVGTARGET2PRICERATIO,AVGVOLUME,AVGVOLUME_USD,CHANGEOPENPERC,CHANGEPERC,EMA_20,EMA_50,EMA_100,EMA_200,PRICE_VS_EMA_20,PRICE_VS_EMA_50,PRICE_VS_EMA_100,PRICE_VS_EMA_200,DAYSTOCOVER,DIVIB,DIVYIELD,DIVYIELDIB,FEERATE,FIRSTTRADEDATE,GROWTHRATE,HALTED,HASOPTIONS,HISTDIVIB,HISTDIVYIELDIB,IMBALANCE,IMBALANCEADVRATIOPERC,IMPVOLAT,IMPVOLATOVERHIST,INSIDEROFFLOATPERC,INSTITUTIONALOFFLOATPERC,MACD,MACD_SIGNAL,MACD_HISTOGRAM,MKTCAP,MKTCAP_USD,NEXTDIVAMOUNT,NEXTDIVDATE,NUMPRICETARGETS,NUMRATINGS,NUMSHARESINSIDER,NUMSHARESINSTITUTIONAL,NUMSHARESSHORT,OPENGAPPERC,OPTVOLUME,OPTVOLUMEPCRATIO,PERATIO,PILOT,PPO,PPO_SIGNAL,PPO_HISTOGRAM,PRICE,PRICE2BK,PRICE2TANBK,PRICERANGE,PRICE_USD,QUICKRATIO,REBATERATE,REGIMBALANCE,REGIMBALANCEADVRATIOPERC,RETEQUITY,SHORTABLESHARES,SHORTOFFLOATPERC,SHORTSALERESTRICTED,SIC,ISSUER_COUNTRY_CODE,SOCSACT,SOCSNET,STKTYPE,STVOLUME_3MIN,STVOLUME_5MIN,STVOLUME_10MIN,TRADECOUNT,TRADERATE,UNSHORTABLE,VOLUME,VOLUMERATE,VOLUME_USD,RCGLTCLASS,RCGLTENDDATE,RCGLTIVALUE,RCGLTTRADE,RCGITCLASS,RCGITENDDATE,RCGITIVALUE,RCGITTRADE,RCGSTCLASS,RCGSTENDDATE,RCGSTIVALUE,RCGSTTRADE",
|
|
41
|
+
# :group=>"STK.GLOBAL",
|
|
42
|
+
# :shortName=>"US",
|
|
43
|
+
# :cloudScanNotSupported=>"false"}
|
|
44
|
+
def instruments
|
|
45
|
+
@data[:xml][:ScanParameterResponse][:InstrumentList].first[:Instrument]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# returns a List of Hashes specifing ScanTypes
|
|
49
|
+
# > C.received[:ScannerParameters].first.scan_types.first
|
|
50
|
+
# => {:displayName=>"Assets Under Management (AltaVista) Desc",
|
|
51
|
+
# :scanCode=>"SCAN_etfAssets_DESC",
|
|
52
|
+
# :instruments=>"ETF.EQ.US,ETF.FI.US",
|
|
53
|
+
# :absoluteColumns=>"false",
|
|
54
|
+
# :Columns=>{:ColumnSetRef=>{:colId=>"0", :name=>"PctPerf", :display=>"false", :displayType=>"DATA"},
|
|
55
|
+
# :Column=>{:colId=>"6031", :name=>"Assets Under Management", :display=>"true", :displayType=>"DATA"}},
|
|
56
|
+
# :supportsSorting=>"true",
|
|
57
|
+
# :respSizeLimit=>"2147483647", :snapshotSizeLimit=>"2147483647",
|
|
58
|
+
# :searchDefault=>"false", :access=>"unrestricted"}
|
|
59
|
+
#
|
|
60
|
+
|
|
61
|
+
def scan_types
|
|
62
|
+
@data[:xml][:ScanParameterResponse][:ScanTypeList][:ScanType]
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Receives the current system time on the server side.
|
|
67
|
+
CurrentTime = def_message 49, [:time, :int] # long!
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
HeadTimeStamp = def_message( [88, 0], [:request_id, :int], [:date, :int_date] ) do
|
|
71
|
+
# def to_human
|
|
72
|
+
"<#{self.message_type}:" +
|
|
73
|
+
"Request #{request_id}, First Historical Datapoint @ #{date.to_s}«"
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# Receive Reuters global fundamental market data. There must be a subscription to
|
|
77
|
+
# Reuters Fundamental set up in Account Management before you can receive this data.
|
|
78
|
+
FundamentalData = def_message 51, [:request_id, :int], [:xml, :xml]
|
|
79
|
+
|
|
80
|
+
ContractDataEnd = def_message 52, [:request_id, :int]
|
|
81
|
+
|
|
82
|
+
OpenOrderEnd = def_message 53
|
|
83
|
+
|
|
84
|
+
AccountDownloadEnd = def_message 54, [:account_name, :string]
|
|
85
|
+
|
|
86
|
+
ExecutionDataEnd = def_message 55, [:request_id, :int]
|
|
87
|
+
|
|
88
|
+
MarketDataType = def_message 58, [:request_id, :int], [:market_data_type, :int] do
|
|
89
|
+
"<#{self.message_type}:" +
|
|
90
|
+
" switched to »#{MARKET_DATA_TYPES[market_data_type]}«" # to_human
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
CommissionReport =
|
|
94
|
+
def_message 59, [:exec_id, :string],
|
|
95
|
+
[:commission, :decimal], # Commission amount.
|
|
96
|
+
[:currency, :string], # Commission currency
|
|
97
|
+
[:realized_pnl, :decimal_max],
|
|
98
|
+
[:yield, :decimal_max],
|
|
99
|
+
[:yield_redemption_date, :int] # YYYYMMDD format
|
|
100
|
+
|
|
101
|
+
SecurityDefinitionOptionParameter = OptionChainDefinition = def_message [75,0] ,
|
|
102
|
+
[:request_id, :int],
|
|
103
|
+
[:exchange, :string],
|
|
104
|
+
[:con_id, :int], # underlying_con_id
|
|
105
|
+
[:trading_class, :string],
|
|
106
|
+
[:multiplier, :int]
|
|
107
|
+
|
|
108
|
+
class OptionChainDefinition
|
|
109
|
+
using IB::Support # defines tws-method for Array (socket.rb)
|
|
110
|
+
def load
|
|
111
|
+
super
|
|
112
|
+
load_map [:expirations, :array, proc { @buffer.read_date }],
|
|
113
|
+
[:strikes, :array, proc { @buffer.read_decimal } ]
|
|
114
|
+
end
|
|
115
|
+
def expirations
|
|
116
|
+
@data[:expirations]
|
|
117
|
+
end
|
|
118
|
+
def strikes
|
|
119
|
+
@data[:strikes]
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def to_human
|
|
123
|
+
"OptionChainDefinition #{trading_class}@#{exchange} [#{multiplier} X ] strikes: #{strikes.first} - #{strikes.last} expirations: #{expirations.first} - #{expirations.last}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
OptionChainDefinitionEnd = SecurityDefinitionOptionParameterEnd = def_message [76,0 ],
|
|
128
|
+
[ :request_id, :int ]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
#<- 1-9-789--USD-CASH-----IDEALPRO--CAD------
|
|
132
|
+
#-> ---81-123-5.0E-5--0-
|
|
133
|
+
|
|
134
|
+
MarketDepthExchanges = def_message [80,0],
|
|
135
|
+
[ :request_id, :int ]
|
|
136
|
+
|
|
137
|
+
TickRequestParameters = def_message [81, 0], [ :ticker_id, :int ],
|
|
138
|
+
[ :min_tick, :decimal],
|
|
139
|
+
[ :exchange, :string ],
|
|
140
|
+
[ :snapshot_permissions, :int ]
|
|
141
|
+
# class TickRequestParameters
|
|
142
|
+
# def load
|
|
143
|
+
# simple_load
|
|
144
|
+
# end
|
|
145
|
+
# end
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
RequestManagedAccounts = def_message 17
|
|
149
|
+
AccountSummaryEnd = def_message 64
|
|
150
|
+
|
|
151
|
+
PositionDataEnd = def_message 62
|
|
152
|
+
|
|
153
|
+
PositionsMultiEnd = def_message 72
|
|
154
|
+
|
|
155
|
+
TickSnapshotEnd = def_message 57, [:ticker_id, :int]
|
|
156
|
+
|
|
157
|
+
AccountUpdatesMultiEnd = def_message 74
|
|
158
|
+
|
|
159
|
+
AccountUpdateTime = def_message 8, [:time_stamp, :string]
|
|
160
|
+
|
|
161
|
+
AccountValue = def_message([6, 2], AccountMessage,
|
|
162
|
+
[:account_value, :key, :symbol],
|
|
163
|
+
[:account_value, :value, :string],
|
|
164
|
+
[:account_value, :currency, :string],
|
|
165
|
+
[:account, :string])
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
AccountUpdatesMulti = def_message( 73,
|
|
169
|
+
[ :request_id, :int ],
|
|
170
|
+
[ :account , :string ],
|
|
171
|
+
[ :model, :string ],
|
|
172
|
+
[ :key , :string ],
|
|
173
|
+
[ :value , :float],
|
|
174
|
+
[ :currency, :string ])
|
|
175
|
+
AccountSummary = def_message(63, AccountMessage,
|
|
176
|
+
[:request_id, :int],
|
|
177
|
+
[ :account, :string ],
|
|
178
|
+
[:account_value, :key, :symbol],
|
|
179
|
+
[:account_value, :value, :string],
|
|
180
|
+
[:account_value, :currency, :string]
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
### Require standalone source files for more complex message classes:
|
|
184
|
+
|
|
185
|
+
# require 'ib/messages/incoming/alert'
|
|
186
|
+
# require 'ib/messages/incoming/contract_data'
|
|
187
|
+
# require 'ib/messages/incoming/delta_neutral_validation'
|
|
188
|
+
# require 'ib/messages/incoming/execution_data'
|
|
189
|
+
# require 'ib/messages/incoming/historical_data'
|
|
190
|
+
# require 'ib/messages/incoming/market_depths'
|
|
191
|
+
# require 'ib/messages/incoming/next_valid_id'
|
|
192
|
+
# require 'ib/messages/incoming/open_order'
|
|
193
|
+
# require 'ib/messages/incoming/order_status'
|
|
194
|
+
# require 'ib/messages/incoming/account_value'
|
|
195
|
+
# require 'ib/messages/incoming/portfolio_value'
|
|
196
|
+
# require 'ib/messages/incoming/real_time_bar'
|
|
197
|
+
# require 'ib/messages/incoming/scanner_data'
|
|
198
|
+
# require 'ib/messages/incoming/ticks'
|
|
199
|
+
#
|
|
200
|
+
end # module Incoming
|
|
201
|
+
end # module Messages
|
|
202
|
+
end # module IB
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
__END__
|
|
206
|
+
// incoming msg id's
|
|
207
|
+
## api 9.71v (python)
|
|
208
|
+
# incoming msg id's
|
|
209
|
+
class IN:
|
|
210
|
+
TICK_PRICE = 1
|
|
211
|
+
TICK_SIZE = 2
|
|
212
|
+
ORDER_STATUS = 3
|
|
213
|
+
ERR_MSG = 4
|
|
214
|
+
OPEN_ORDER = 5
|
|
215
|
+
ACCT_VALUE = 6
|
|
216
|
+
PORTFOLIO_VALUE = 7
|
|
217
|
+
ACCT_UPDATE_TIME = 8
|
|
218
|
+
NEXT_VALID_ID = 9
|
|
219
|
+
CONTRACT_DATA = 10
|
|
220
|
+
EXECUTION_DATA = 11
|
|
221
|
+
MARKET_DEPTH = 12
|
|
222
|
+
MARKET_DEPTH_L2 = 13
|
|
223
|
+
NEWS_BULLETINS = 14
|
|
224
|
+
MANAGED_ACCTS = 15
|
|
225
|
+
RECEIVE_FA = 16
|
|
226
|
+
HISTORICAL_DATA = 17
|
|
227
|
+
BOND_CONTRACT_DATA = 18
|
|
228
|
+
SCANNER_PARAMETERS = 19
|
|
229
|
+
SCANNER_DATA = 20
|
|
230
|
+
TICK_OPTION_COMPUTATION = 21
|
|
231
|
+
TICK_GENERIC = 45
|
|
232
|
+
TICK_STRING = 46
|
|
233
|
+
TICK_EFP = 47
|
|
234
|
+
CURRENT_TIME = 49
|
|
235
|
+
REAL_TIME_BARS = 50
|
|
236
|
+
FUNDAMENTAL_DATA = 51
|
|
237
|
+
CONTRACT_DATA_END = 52
|
|
238
|
+
OPEN_ORDER_END = 53
|
|
239
|
+
ACCT_DOWNLOAD_END = 54
|
|
240
|
+
EXECUTION_DATA_END = 55
|
|
241
|
+
DELTA_NEUTRAL_VALIDATION = 56
|
|
242
|
+
TICK_SNAPSHOT_END = 57
|
|
243
|
+
MARKET_DATA_TYPE = 58
|
|
244
|
+
COMMISSION_REPORT = 59 ##
|
|
245
|
+
### const below are new in api 9.71
|
|
246
|
+
POSITION_DATA = 61
|
|
247
|
+
POSITION_END = 62
|
|
248
|
+
ACCOUNT_SUMMARY = 63
|
|
249
|
+
ACCOUNT_SUMMARY_END = 64
|
|
250
|
+
VERIFY_MESSAGE_API = 65
|
|
251
|
+
VERIFY_COMPLETED = 66
|
|
252
|
+
DISPLAY_GROUP_LIST = 67
|
|
253
|
+
DISPLAY_GROUP_UPDATED = 68
|
|
254
|
+
VERIFY_AND_AUTH_MESSAGE_API = 69
|
|
255
|
+
VERIFY_AND_AUTH_COMPLETED = 70
|
|
256
|
+
POSITION_MULTI = 71
|
|
257
|
+
POSITION_MULTI_END = 72
|
|
258
|
+
ACCOUNT_UPDATE_MULTI = 73
|
|
259
|
+
ACCOUNT_UPDATE_MULTI_END = 74
|
|
260
|
+
SECURITY_DEFINITION_OPTION_PARAMETER = 75
|
|
261
|
+
SECURITY_DEFINITION_OPTION_PARAMETER_END = 76
|
|
262
|
+
SOFT_DOLLAR_TIERS = 77
|
|
263
|
+
FAMILY_CODES = 78
|
|
264
|
+
SYMBOL_SAMPLES = 79
|
|
265
|
+
MKT_DEPTH_EXCHANGES = 80
|
|
266
|
+
TICK_REQ_PARAMS = 81
|
|
267
|
+
SMART_COMPONENTS = 82
|
|
268
|
+
NEWS_ARTICLE = 83
|
|
269
|
+
TICK_NEWS = 84
|
|
270
|
+
NEWS_PROVIDERS = 85
|
|
271
|
+
HISTORICAL_NEWS = 86
|
|
272
|
+
HISTORICAL_NEWS_END = 87
|
|
273
|
+
HEAD_TIMESTAMP = 88
|
|
274
|
+
HISTOGRAM_DATA = 89
|
|
275
|
+
HISTORICAL_DATA_UPDATE = 90
|
|
276
|
+
REROUTE_MKT_DATA_REQ = 91
|
|
277
|
+
REROUTE_MKT_DEPTH_REQ = 92
|
|
278
|
+
MARKET_RULE = 93
|
|
279
|
+
PNL = 94
|
|
280
|
+
PNL_SINGLE = 95
|
|
281
|
+
HISTORICAL_TICKS = 96
|
|
282
|
+
HISTORICAL_TICKS_BID_ASK = 97
|
|
283
|
+
HISTORICAL_TICKS_LAST = 98
|
|
284
|
+
TICK_BY_TICK = 99
|
|
285
|
+
# VER 10
|
|
286
|
+
ORDER_BOUND = 100
|
|
287
|
+
COMPLETED_ORDER = 101
|
|
288
|
+
COMPLETED_ORDERS_END = 102
|
|
289
|
+
REPLACE_FA_END = 103
|
|
290
|
+
WSH_META_DATA = 104
|
|
291
|
+
WSH_EVENT_DATA = 105
|
|
292
|
+
HISTORICAL_SCHEDULE = 106
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
module IB
|
|
2
|
+
module Messages
|
|
3
|
+
module Outgoing
|
|
4
|
+
|
|
5
|
+
# Container for specific message classes, keyed by their message_ids
|
|
6
|
+
Classes = {}
|
|
7
|
+
|
|
8
|
+
class AbstractMessage < IB::Messages::AbstractMessage
|
|
9
|
+
|
|
10
|
+
def initialize data={}
|
|
11
|
+
@data = data
|
|
12
|
+
@created_at = Time.now
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# This causes the message to send itself over the server socket in server[:socket].
|
|
16
|
+
# "server" is the @server instance variable from the IB object.
|
|
17
|
+
# You can also use this to e.g. get the server version number.
|
|
18
|
+
#
|
|
19
|
+
# Subclasses can either override this method for precise control over how
|
|
20
|
+
# stuff gets sent to the server, or else define a method encode() that returns
|
|
21
|
+
# an Array of elements that ought to be sent to the server by calling to_s on
|
|
22
|
+
# each one and postpending a '\0'.
|
|
23
|
+
#
|
|
24
|
+
def send_to socket
|
|
25
|
+
Connection.logger.debug to_s
|
|
26
|
+
socket.send_messages self.preprocess #.each {|data| socket.write_data data}
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Same message representation as logged by TWS into API messages log file
|
|
30
|
+
def to_s
|
|
31
|
+
self.preprocess.join('-')
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Pre-process encoded message Array before sending into socket, such as
|
|
35
|
+
# changing booleans into 0/1 and stuff
|
|
36
|
+
def preprocess
|
|
37
|
+
self.encode.flatten.reject{ |x| x == "do not include"}.map {|data| data == true ? 1 : data == false ? 0 : data }
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Encode message content into (possibly, nested) Array of values.
|
|
41
|
+
# At minimum, encoded Outgoing message contains message_id and version.
|
|
42
|
+
# Most messages also contain (ticker, request or order) :id.
|
|
43
|
+
# Then, content of @data Hash is encoded per instructions in data_map.
|
|
44
|
+
# This method may be modified by message subclasses!
|
|
45
|
+
#
|
|
46
|
+
# If the version is zero, omit its apperance (for redesigned message-types as place-order, historical-data, etc)
|
|
47
|
+
def encode
|
|
48
|
+
## create a proper request_id and erase :id and :ticker_id if nessesary
|
|
49
|
+
if self.class.properties?.include?(:request_id)
|
|
50
|
+
@data[:request_id] = if @data[:request_id].blank? && @data[:ticker_id].blank? && @data[:id].blank?
|
|
51
|
+
rand(9999)
|
|
52
|
+
else
|
|
53
|
+
@data[:id] || @data[:ticker_id] || @data[:request_id]
|
|
54
|
+
end
|
|
55
|
+
@data[:id] = @data[:ticker_id] = nil
|
|
56
|
+
end
|
|
57
|
+
[
|
|
58
|
+
self.class.version.zero? ? self.class.message_id : [ self.class.message_id, self.class.version ],
|
|
59
|
+
# include :id, :ticker_id, :local_id or :order_id as first field of the message (if present)
|
|
60
|
+
@data[:id] || @data[:ticker_id] ||# @data[:request_id] || # id, ticker_id, local_id, order_id
|
|
61
|
+
@data[:local_id] || @data[:order_id] || [], # do not appear in data_map
|
|
62
|
+
self.class.data_map.map do |(field, default_method, args)| # but request_id does
|
|
63
|
+
case
|
|
64
|
+
when default_method.nil?
|
|
65
|
+
@data[field]
|
|
66
|
+
|
|
67
|
+
when default_method.is_a?(Symbol) # method name with args
|
|
68
|
+
@data[field].send default_method, *args
|
|
69
|
+
|
|
70
|
+
when default_method.respond_to?(:call) # callable with args
|
|
71
|
+
default_method.call @data[field], *args
|
|
72
|
+
|
|
73
|
+
else # default
|
|
74
|
+
@data[field].nil? ? default_method : @data[field] # may be false still
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
]
|
|
78
|
+
# TWS wants to receive booleans as 1 or 0
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end # AbstractMessage
|
|
82
|
+
end # module Outgoing
|
|
83
|
+
end # module Messages
|
|
84
|
+
end # module IB
|