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.
Files changed (161) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +52 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +7 -0
  5. data/CLAUDE.md +131 -0
  6. data/CODE_OF_CONDUCT.md +74 -0
  7. data/Gemfile +17 -0
  8. data/Gemfile.lock +120 -0
  9. data/Guardfile +24 -0
  10. data/LICENSE +674 -0
  11. data/LLM_GUIDE.md +388 -0
  12. data/README.md +114 -0
  13. data/Rakefile +11 -0
  14. data/VERSION +1 -0
  15. data/api.gemspec +50 -0
  16. data/bin/console +96 -0
  17. data/bin/console.yml +3 -0
  18. data/bin/setup +8 -0
  19. data/bin/simple +91 -0
  20. data/changelog.md +32 -0
  21. data/conditions/ib/execution_condition.rb +31 -0
  22. data/conditions/ib/margin_condition.rb +28 -0
  23. data/conditions/ib/order_condition.rb +29 -0
  24. data/conditions/ib/percent_change_condition.rb +34 -0
  25. data/conditions/ib/price_condition.rb +44 -0
  26. data/conditions/ib/time_condition.rb +42 -0
  27. data/conditions/ib/volume_condition.rb +36 -0
  28. data/lib/class_extensions.rb +167 -0
  29. data/lib/ib/base.rb +109 -0
  30. data/lib/ib/base_properties.rb +178 -0
  31. data/lib/ib/connection.rb +573 -0
  32. data/lib/ib/constants.rb +402 -0
  33. data/lib/ib/contract.rb +30 -0
  34. data/lib/ib/errors.rb +52 -0
  35. data/lib/ib/messages/abstract_message.rb +68 -0
  36. data/lib/ib/messages/incoming/abstract_message.rb +116 -0
  37. data/lib/ib/messages/incoming/abstract_tick.rb +25 -0
  38. data/lib/ib/messages/incoming/account_message.rb +26 -0
  39. data/lib/ib/messages/incoming/alert.rb +34 -0
  40. data/lib/ib/messages/incoming/contract_data.rb +105 -0
  41. data/lib/ib/messages/incoming/contract_message.rb +13 -0
  42. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  43. data/lib/ib/messages/incoming/execution_data.rb +50 -0
  44. data/lib/ib/messages/incoming/histogram_data.rb +30 -0
  45. data/lib/ib/messages/incoming/historical_data.rb +65 -0
  46. data/lib/ib/messages/incoming/historical_data_update.rb +50 -0
  47. data/lib/ib/messages/incoming/managed_accounts.rb +21 -0
  48. data/lib/ib/messages/incoming/market_depth.rb +34 -0
  49. data/lib/ib/messages/incoming/market_depth_l2.rb +15 -0
  50. data/lib/ib/messages/incoming/next_valid_id.rb +19 -0
  51. data/lib/ib/messages/incoming/open_order.rb +290 -0
  52. data/lib/ib/messages/incoming/order_status.rb +85 -0
  53. data/lib/ib/messages/incoming/portfolio_value.rb +47 -0
  54. data/lib/ib/messages/incoming/position_data.rb +21 -0
  55. data/lib/ib/messages/incoming/positions_multi.rb +15 -0
  56. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  57. data/lib/ib/messages/incoming/receive_fa.rb +30 -0
  58. data/lib/ib/messages/incoming/scanner_data.rb +54 -0
  59. data/lib/ib/messages/incoming/tick_by_tick.rb +77 -0
  60. data/lib/ib/messages/incoming/tick_efp.rb +18 -0
  61. data/lib/ib/messages/incoming/tick_generic.rb +12 -0
  62. data/lib/ib/messages/incoming/tick_option.rb +60 -0
  63. data/lib/ib/messages/incoming/tick_price.rb +60 -0
  64. data/lib/ib/messages/incoming/tick_size.rb +55 -0
  65. data/lib/ib/messages/incoming/tick_string.rb +13 -0
  66. data/lib/ib/messages/incoming.rb +292 -0
  67. data/lib/ib/messages/outgoing/abstract_message.rb +84 -0
  68. data/lib/ib/messages/outgoing/bar_request_message.rb +247 -0
  69. data/lib/ib/messages/outgoing/new-place-order.rb +193 -0
  70. data/lib/ib/messages/outgoing/old-place-order.rb +147 -0
  71. data/lib/ib/messages/outgoing/place_order.rb +149 -0
  72. data/lib/ib/messages/outgoing/request_account_summary.rb +79 -0
  73. data/lib/ib/messages/outgoing/request_historical_data.rb +182 -0
  74. data/lib/ib/messages/outgoing/request_market_data.rb +102 -0
  75. data/lib/ib/messages/outgoing/request_market_depth.rb +57 -0
  76. data/lib/ib/messages/outgoing/request_real_time_bars.rb +48 -0
  77. data/lib/ib/messages/outgoing/request_scanner_subscription.rb +73 -0
  78. data/lib/ib/messages/outgoing/request_tick_by_tick_data.rb +21 -0
  79. data/lib/ib/messages/outgoing.rb +410 -0
  80. data/lib/ib/messages.rb +139 -0
  81. data/lib/ib/order_condition.rb +26 -0
  82. data/lib/ib/plugins.rb +27 -0
  83. data/lib/ib/prepare_data.rb +61 -0
  84. data/lib/ib/raw_message_parser.rb +99 -0
  85. data/lib/ib/socket.rb +83 -0
  86. data/lib/ib/support.rb +236 -0
  87. data/lib/ib/version.rb +6 -0
  88. data/lib/ib-api.rb +44 -0
  89. data/lib/server_versions.rb +145 -0
  90. data/lib/support/array_function.rb +28 -0
  91. data/lib/support/logging.rb +45 -0
  92. data/models/ib/account.rb +72 -0
  93. data/models/ib/account_value.rb +33 -0
  94. data/models/ib/bag.rb +55 -0
  95. data/models/ib/bar.rb +31 -0
  96. data/models/ib/combo_leg.rb +127 -0
  97. data/models/ib/contract.rb +411 -0
  98. data/models/ib/contract_detail.rb +118 -0
  99. data/models/ib/execution.rb +67 -0
  100. data/models/ib/forex.rb +12 -0
  101. data/models/ib/future.rb +64 -0
  102. data/models/ib/index.rb +14 -0
  103. data/models/ib/option.rb +149 -0
  104. data/models/ib/option_detail.rb +84 -0
  105. data/models/ib/order.rb +720 -0
  106. data/models/ib/order_state.rb +155 -0
  107. data/models/ib/portfolio_value.rb +86 -0
  108. data/models/ib/spread.rb +176 -0
  109. data/models/ib/stock.rb +25 -0
  110. data/models/ib/underlying.rb +32 -0
  111. data/plugins/ib/advanced-account.rb +442 -0
  112. data/plugins/ib/alerts/base-alert.rb +125 -0
  113. data/plugins/ib/alerts/gateway-alerts.rb +15 -0
  114. data/plugins/ib/alerts/order-alerts.rb +73 -0
  115. data/plugins/ib/auto-adjust.rb +0 -0
  116. data/plugins/ib/connection-tools.rb +122 -0
  117. data/plugins/ib/eod.rb +326 -0
  118. data/plugins/ib/greeks.rb +102 -0
  119. data/plugins/ib/managed-accounts.rb +274 -0
  120. data/plugins/ib/market-price.rb +150 -0
  121. data/plugins/ib/option-chain.rb +167 -0
  122. data/plugins/ib/order-flow.rb +157 -0
  123. data/plugins/ib/order-prototypes/abstract.rb +67 -0
  124. data/plugins/ib/order-prototypes/adaptive.rb +40 -0
  125. data/plugins/ib/order-prototypes/all-in-one.rb +46 -0
  126. data/plugins/ib/order-prototypes/combo.rb +46 -0
  127. data/plugins/ib/order-prototypes/forex.rb +40 -0
  128. data/plugins/ib/order-prototypes/limit.rb +193 -0
  129. data/plugins/ib/order-prototypes/market.rb +116 -0
  130. data/plugins/ib/order-prototypes/pegged.rb +169 -0
  131. data/plugins/ib/order-prototypes/premarket.rb +31 -0
  132. data/plugins/ib/order-prototypes/stop.rb +202 -0
  133. data/plugins/ib/order-prototypes/volatility.rb +39 -0
  134. data/plugins/ib/order-prototypes.rb +118 -0
  135. data/plugins/ib/probability-of-expiring.rb +109 -0
  136. data/plugins/ib/process-orders.rb +155 -0
  137. data/plugins/ib/roll.rb +86 -0
  138. data/plugins/ib/spread-prototypes/butterfly.rb +77 -0
  139. data/plugins/ib/spread-prototypes/calendar.rb +97 -0
  140. data/plugins/ib/spread-prototypes/stock-spread.rb +56 -0
  141. data/plugins/ib/spread-prototypes/straddle.rb +70 -0
  142. data/plugins/ib/spread-prototypes/strangle.rb +93 -0
  143. data/plugins/ib/spread-prototypes/vertical.rb +83 -0
  144. data/plugins/ib/spread-prototypes.rb +70 -0
  145. data/plugins/ib/symbols/abstract.rb +136 -0
  146. data/plugins/ib/symbols/bonds.rb +28 -0
  147. data/plugins/ib/symbols/cfd.rb +19 -0
  148. data/plugins/ib/symbols/combo.rb +46 -0
  149. data/plugins/ib/symbols/commodity.rb +17 -0
  150. data/plugins/ib/symbols/forex.rb +41 -0
  151. data/plugins/ib/symbols/futures.rb +127 -0
  152. data/plugins/ib/symbols/index.rb +43 -0
  153. data/plugins/ib/symbols/options.rb +99 -0
  154. data/plugins/ib/symbols/stocks.rb +44 -0
  155. data/plugins/ib/symbols/version.rb +5 -0
  156. data/plugins/ib/symbols.rb +118 -0
  157. data/plugins/ib/verify.rb +226 -0
  158. data/symbols/w20.yml +210 -0
  159. data/t.txt +20 -0
  160. data/update.md +71 -0
  161. metadata +327 -0
@@ -0,0 +1,12 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+ extend Messages # def_message macros
5
+
6
+ TickGeneric = def_message [45, 6], AbstractTick,
7
+ [:ticker_id, :int],
8
+ [:tick_type, :int],
9
+ [:value, :float]
10
+ end
11
+ end
12
+ end
@@ -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,13 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+ extend Messages # def_message macros
5
+
6
+ TickString = def_message [46, 6], AbstractTick,
7
+ [:ticker_id, :int],
8
+ [:tick_type, :int],
9
+ [:value, :string]
10
+ end
11
+ end
12
+ end
13
+
@@ -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