my-ib-api 0.0.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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/lib/ib-api.rb +10 -0
  3. data/lib/ib/base.rb +99 -0
  4. data/lib/ib/base_properties.rb +154 -0
  5. data/lib/ib/connection.rb +327 -0
  6. data/lib/ib/constants.rb +334 -0
  7. data/lib/ib/db.rb +29 -0
  8. data/lib/ib/engine.rb +35 -0
  9. data/lib/ib/errors.rb +40 -0
  10. data/lib/ib/extensions.rb +72 -0
  11. data/lib/ib/flex.rb +106 -0
  12. data/lib/ib/logger.rb +25 -0
  13. data/lib/ib/messages.rb +88 -0
  14. data/lib/ib/messages/abstract_message.rb +89 -0
  15. data/lib/ib/messages/incoming.rb +134 -0
  16. data/lib/ib/messages/incoming/abstract_message.rb +99 -0
  17. data/lib/ib/messages/incoming/alert.rb +34 -0
  18. data/lib/ib/messages/incoming/contract_data.rb +102 -0
  19. data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
  20. data/lib/ib/messages/incoming/execution_data.rb +54 -0
  21. data/lib/ib/messages/incoming/historical_data.rb +55 -0
  22. data/lib/ib/messages/incoming/market_depths.rb +44 -0
  23. data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
  24. data/lib/ib/messages/incoming/open_order.rb +232 -0
  25. data/lib/ib/messages/incoming/order_status.rb +81 -0
  26. data/lib/ib/messages/incoming/portfolio_value.rb +39 -0
  27. data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
  28. data/lib/ib/messages/incoming/scanner_data.rb +53 -0
  29. data/lib/ib/messages/incoming/ticks.rb +131 -0
  30. data/lib/ib/messages/outgoing.rb +331 -0
  31. data/lib/ib/messages/outgoing/abstract_message.rb +73 -0
  32. data/lib/ib/messages/outgoing/bar_requests.rb +189 -0
  33. data/lib/ib/messages/outgoing/place_order.rb +141 -0
  34. data/lib/ib/model.rb +6 -0
  35. data/lib/ib/models.rb +10 -0
  36. data/lib/ib/requires.rb +9 -0
  37. data/lib/ib/socket.rb +81 -0
  38. data/lib/ib/symbols.rb +35 -0
  39. data/lib/ib/symbols/bonds.rb +28 -0
  40. data/lib/ib/symbols/forex.rb +41 -0
  41. data/lib/ib/symbols/futures.rb +117 -0
  42. data/lib/ib/symbols/options.rb +39 -0
  43. data/lib/ib/symbols/stocks.rb +37 -0
  44. data/lib/ib/version.rb +6 -0
  45. data/lib/models/ib/bag.rb +51 -0
  46. data/lib/models/ib/bar.rb +45 -0
  47. data/lib/models/ib/combo_leg.rb +103 -0
  48. data/lib/models/ib/contract.rb +292 -0
  49. data/lib/models/ib/contract_detail.rb +89 -0
  50. data/lib/models/ib/execution.rb +65 -0
  51. data/lib/models/ib/option.rb +60 -0
  52. data/lib/models/ib/order.rb +391 -0
  53. data/lib/models/ib/order_state.rb +128 -0
  54. data/lib/models/ib/underlying.rb +34 -0
  55. metadata +96 -0
@@ -0,0 +1,81 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # :status - String: Displays the order status. Possible values include:
6
+ # - PendingSubmit - indicates that you have transmitted the order, but
7
+ # have not yet received confirmation that it has been accepted by the
8
+ # order destination. NOTE: This order status is NOT sent back by TWS
9
+ # and should be explicitly set by YOU when an order is submitted.
10
+ # - PendingCancel - indicates that you have sent a request to cancel
11
+ # the order but have not yet received cancel confirmation from the
12
+ # order destination. At this point, your order cancel is not confirmed.
13
+ # You may still receive an execution while your cancellation request
14
+ # is pending. NOTE: This order status is not sent back by TWS and
15
+ # should be explicitly set by YOU when an order is canceled.
16
+ # - PreSubmitted - indicates that a simulated order type has been
17
+ # accepted by the IB system and that this order has yet to be elected.
18
+ # The order is held in the IB system until the election criteria are
19
+ # met. At that time the order is transmitted to the order destination
20
+ # as specified.
21
+ # - Submitted - indicates that your order has been accepted at the order
22
+ # destination and is working.
23
+ # - Cancelled - indicates that the balance of your order has been
24
+ # confirmed canceled by the IB system. This could occur unexpectedly
25
+ # when IB or the destination has rejected your order.
26
+ # - ApiCancelled - canceled via API
27
+ # - Filled - indicates that the order has been completely filled.
28
+ # - Inactive - indicates that the order has been accepted by the system
29
+ # (simulated orders) or an exchange (native orders) but that currently
30
+ # the order is inactive due to system, exchange or other issues.
31
+ # :why_held - This property contains the comma-separated list of reasons for
32
+ # order to be held. For example, when TWS is trying to locate shares for
33
+ # a short sell, the value used to indicate this is 'locate'.
34
+ OrderStatus = def_message [3, 6],
35
+ [:order_state, :local_id, :int],
36
+ [:order_state, :status, :string],
37
+ [:order_state, :filled, :int],
38
+ [:order_state, :remaining, :int],
39
+ [:order_state, :average_fill_price, :decimal],
40
+ [:order_state, :perm_id, :int],
41
+ [:order_state, :parent_id, :int],
42
+ [:order_state, :last_fill_price, :decimal],
43
+ [:order_state, :client_id, :int],
44
+ [:order_state, :why_held, :string]
45
+ class OrderStatus
46
+
47
+ def order_state
48
+ @order_state ||= IB::OrderState.new @data[:order_state]
49
+ end
50
+
51
+ # Accessors to make OpenOrder and OrderStatus messages API-compatible
52
+ def client_id
53
+ order_state.client_id
54
+ end
55
+
56
+ def parent_id
57
+ order_state.parent_id
58
+ end
59
+
60
+ def perm_id
61
+ order_state.perm_id
62
+ end
63
+
64
+ def local_id
65
+ order_state.local_id
66
+ end
67
+
68
+ alias order_id local_id
69
+
70
+ def status
71
+ order_state.status
72
+ end
73
+
74
+ def to_human
75
+ "<OrderStatus: #{order_state}>"
76
+ end
77
+
78
+ end # class OrderStatus
79
+ end # module Incoming
80
+ end # module Messages
81
+ end # module IB
@@ -0,0 +1,39 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ PortfolioValue = def_message [7, 7],
6
+ [:contract, :con_id, :int],
7
+ [:contract, :symbol, :string],
8
+ [:contract, :sec_type, :string],
9
+ [:contract, :expiry, :string],
10
+ [:contract, :strike, :decimal],
11
+ [:contract, :right, :string],
12
+ [:contract, :multiplier, :string],
13
+ [:contract, :primary_exchange, :string],
14
+ [:contract, :currency, :string],
15
+ [:contract, :local_symbol, :string],
16
+ [:position, :int],
17
+ [:market_price, :decimal],
18
+ [:market_value, :decimal],
19
+ [:average_cost, :decimal],
20
+ [:unrealized_pnl, :decimal_max], # May be nil!
21
+ [:realized_pnl, :decimal_max], # May be nil!
22
+ [:account_name, :string]
23
+ class PortfolioValue
24
+
25
+ def contract
26
+ @contract = IB::Contract.build @data[:contract]
27
+ end
28
+
29
+ def to_human
30
+ "<PortfolioValue: #{contract.to_human} (#{position}): Market #{market_price}" +
31
+ " price #{market_value} value; PnL: #{unrealized_pnl} unrealized," +
32
+ " #{realized_pnl} realized; account #{account_name}>"
33
+ end
34
+ end # PortfolioValue
35
+
36
+
37
+ end # module Incoming
38
+ end # module Messages
39
+ end # module IB
@@ -0,0 +1,32 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # RealTimeBar contains following @data:
6
+ # :request_id - The ID of the *request* to which this is responding
7
+ # :time - The date-time stamp of the start of the bar. The format is offset in
8
+ # seconds from the beginning of 1970, same format as the UNIX epoch time
9
+ # :bar - received RT Bar
10
+ RealTimeBar = def_message [50, 3],
11
+ [:request_id, :int],
12
+ [:bar, :time, :int],
13
+ [:bar, :open, :decimal],
14
+ [:bar, :high, :decimal],
15
+ [:bar, :low, :decimal],
16
+ [:bar, :close, :decimal],
17
+ [:bar, :volume, :int],
18
+ [:bar, :wap, :decimal],
19
+ [:bar, :trades, :int]
20
+ class RealTimeBar
21
+ def bar
22
+ @bar = IB::Bar.new @data[:bar]
23
+ end
24
+
25
+ def to_human
26
+ "<RealTimeBar: #{request_id} #{bar}>"
27
+ end
28
+ end # RealTimeBar
29
+
30
+ end # module Incoming
31
+ end # module Messages
32
+ end # module IB
@@ -0,0 +1,53 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # This method receives the requested market scanner data results.
6
+ # ScannerData contains following @data:
7
+ # :request_id - The ID of the request to which this row is responding
8
+ # :count - Number of data points returned (size of :results).
9
+ # :results - an Array of Hashes, each hash contains a set of
10
+ # data about one scanned Contract:
11
+ # :contract - a full description of the contract (details).
12
+ # :distance - Varies based on query.
13
+ # :benchmark - Varies based on query.
14
+ # :projection - Varies based on query.
15
+ # :legs - Describes combo legs when scan is returning EFP.
16
+ ScannerData = def_message [20, 3],
17
+ [:request_id, :int], # request id
18
+ [:count, :int]
19
+ class ScannerData
20
+ attr_accessor :results
21
+
22
+ def load
23
+ super
24
+
25
+ @results = Array.new(@data[:count]) do |_|
26
+ {:rank => socket.read_int,
27
+ :contract =>
28
+ Contract.build(
29
+ :con_id => socket.read_int,
30
+ :symbol => socket.read_string,
31
+ :sec_type => socket.read_string,
32
+ :expiry => socket.read_string,
33
+ :strike => socket.read_decimal,
34
+ :right => socket.read_string,
35
+ :exchange => socket.read_string,
36
+ :currency => socket.read_string,
37
+ :local_symbol => socket.read_string,
38
+ :contract_detail =>
39
+ IB::ContractDetail.new(
40
+ :market_name => socket.read_string,
41
+ :trading_class => socket.read_string)),
42
+ :distance => socket.read_string,
43
+ :benchmark => socket.read_string,
44
+ :projection => socket.read_string,
45
+ :legs => socket.read_string,
46
+ }
47
+ end
48
+ end
49
+ end # ScannerData
50
+
51
+ end # module Incoming
52
+ end # module Messages
53
+ end # module IB
@@ -0,0 +1,131 @@
1
+ # All message classes related to ticks located here
2
+ module IB
3
+ module Messages
4
+ module Incoming
5
+
6
+ class AbstractTick < AbstractMessage
7
+ # Returns Symbol with a meaningful name for received tick type
8
+ def type
9
+ TICK_TYPES[@data[:tick_type]]
10
+ end
11
+
12
+ def to_human
13
+ "<#{self.message_type} #{type}:" +
14
+ @data.map do |key, value|
15
+ " #{key} #{value}" unless [:version, :ticker_id, :tick_type].include?(key)
16
+ end.compact.join(',') + " >"
17
+ end
18
+ end
19
+
20
+ # The IB code seems to dispatch up to two wrapped objects for this message, a tickPrice
21
+ # and sometimes a tickSize, which seems to be identical to the TICK_SIZE object.
22
+ #
23
+ # Important note from
24
+ # http://chuckcaplan.com/twsapi/index.php/void%20tickPrice%28%29 :
25
+ #
26
+ # "The low you get is NOT the low for the day as you'd expect it
27
+ # to be. It appears IB calculates the low based on all
28
+ # transactions after 4pm the previous day. The most inaccurate
29
+ # results occur when the stock moves up in the 4-6pm aftermarket
30
+ # on the previous day and then gaps open upward in the
31
+ # morning. The low you receive from TWS can be easily be several
32
+ # points different from the actual 9:30am-4pm low for the day in
33
+ # cases like this. If you require a correct traded low for the
34
+ # day, you can't get it from the TWS API. One possible source to
35
+ # help build the right data would be to compare against what Yahoo
36
+ # lists on finance.yahoo.com/q?s=ticker under the "Day's Range"
37
+ # statistics (be careful here, because Yahoo will use anti-Denial
38
+ # of Service techniques to hang your connection if you try to
39
+ # request too many bytes in a short period of time from them). For
40
+ # most purposes, a good enough approach would start by replacing
41
+ # the TWS low for the day with Yahoo's day low when you first
42
+ # start watching a stock ticker; let's call this time T. Then,
43
+ # update your internal low if the bid or ask tick you receive is
44
+ # lower than that for the remainder of the day. You should check
45
+ # against Yahoo again at time T+20min to handle the occasional
46
+ # case where the stock set a new low for the day in between
47
+ # T-20min (the real time your original quote was from, taking into
48
+ # account the delay) and time T. After that you should have a
49
+ # correct enough low for the rest of the day as long as you keep
50
+ # updating based on the bid/ask. It could still get slightly off
51
+ # in a case where a short transaction setting a new low appears in
52
+ # between ticks of data that TWS sends you. The high is probably
53
+ # distorted in the same way the low is, which would throw your
54
+ # results off if the stock traded after-hours and gapped down. It
55
+ # should be corrected in a similar way as described above if this
56
+ # is important to you."
57
+ #
58
+ # IB then emits at most 2 events on eWrapper:
59
+ # tickPrice( tickerId, tickType, price, canAutoExecute)
60
+ # tickSize( tickerId, sizeTickType, size)
61
+ TickPrice = def_message [1, 6], AbstractTick,
62
+ [:ticker_id, :int],
63
+ [:tick_type, :int],
64
+ [:price, :decimal],
65
+ [:size, :int],
66
+ [:can_auto_execute, :int]
67
+
68
+ TickSize = def_message [2, 6], AbstractTick,
69
+ [:ticker_id, :int],
70
+ [:tick_type, :int],
71
+ [:size, :int]
72
+
73
+ TickGeneric = def_message [45, 6], AbstractTick,
74
+ [:ticker_id, :int],
75
+ [:tick_type, :int],
76
+ [:value, :decimal]
77
+
78
+ TickString = def_message [46, 6], AbstractTick,
79
+ [:ticker_id, :int],
80
+ [:tick_type, :int],
81
+ [:value, :string]
82
+
83
+ TickEFP = def_message [47, 6], AbstractTick,
84
+ [:ticker_id, :int],
85
+ [:tick_type, :int],
86
+ [:basis_points, :decimal],
87
+ [:formatted_basis_points, :string],
88
+ [:implied_futures_price, :decimal],
89
+ [:hold_days, :int],
90
+ [:dividend_impact, :decimal],
91
+ [:dividends_to_expiry, :decimal]
92
+
93
+ # This message is received when the market in an option or its underlier moves.
94
+ # TWS option model volatilities, prices, and deltas, along with the present
95
+ # value of dividends expected on that options underlier are received.
96
+ # TickOption message contains following @data:
97
+ # :ticker_id - Id that was specified previously in the call to reqMktData()
98
+ # :tick_type - Specifies the type of option computation (see TICK_TYPES).
99
+ # :implied_volatility - The implied volatility calculated by the TWS option
100
+ # modeler, using the specified :tick_type value.
101
+ # :delta - The option delta value.
102
+ # :option_price - The option price.
103
+ # :pv_dividend - The present value of dividends expected on the options underlier
104
+ # :gamma - The option gamma value.
105
+ # :vega - The option vega value.
106
+ # :theta - The option theta value.
107
+ # :under_price - The price of the underlying.
108
+ TickOptionComputation = TickOption =
109
+ def_message([21, 6], AbstractTick,
110
+ [:ticker_id, :int],
111
+ [:tick_type, :int],
112
+ # What is the "not yet computed" indicator:
113
+ [:implied_volatility, :decimal_limit_1], # -1 and below
114
+ [:delta, :decimal_limit_2], # -2 and below
115
+ [:option_price, :decimal_limit_1], # -1 -"-
116
+ [:pv_dividend, :decimal_limit_1], # -1 -"-
117
+ [:gamma, :decimal_limit_2], # -2 -"-
118
+ [:vega, :decimal_limit_2], # -2 -"-
119
+ [:theta, :decimal_limit_2], # -2 -"-
120
+ [:under_price, :decimal_limit_1]) do
121
+
122
+ "<TickOption #{type} for #{:ticker_id}: underlying @ #{under_price}, "+
123
+ "option @ #{option_price}, IV #{implied_volatility}%, delta #{delta}, " +
124
+ "gamma #{gamma}, vega #{vega}, theta #{theta}, pv_dividend #{pv_dividend}>"
125
+ end
126
+
127
+ TickSnapshotEnd = def_message 57, [:ticker_id, :int]
128
+
129
+ end # module Incoming
130
+ end # module Messages
131
+ end # module IB
@@ -0,0 +1,331 @@
1
+ require 'ib/messages/outgoing/abstract_message'
2
+
3
+ # TODO: Don't instantiate messages, use their classes as just namespace for .encode/decode
4
+
5
+ module IB
6
+ module Messages
7
+
8
+ # Outgoing IB messages (sent to TWS/Gateway)
9
+ module Outgoing
10
+ extend Messages # def_message macros
11
+
12
+ ### Defining (short) Outgoing Message classes for IB:
13
+
14
+ ## Empty messages (no data)
15
+
16
+ # Request the open orders that were placed from THIS client. Each open order
17
+ # will be fed back through the OpenOrder and OrderStatus messages ONCE.
18
+ # NB: Client with a client_id of 0 will also receive the TWS-owned open orders.
19
+ # These orders will be associated with the client and a new orderId will be
20
+ # generated. This association will persist over multiple API and TWS sessions.
21
+ RequestOpenOrders = def_message 5
22
+
23
+ # Request the open orders placed from all clients and also from TWS. Each open
24
+ # order will be fed back through the OpenOrder and OrderStatus messages ONCE.
25
+ # Note this does not re-bind those Orders to requesting Client!
26
+ # Use RequestAutoOpenOrders to request such re-binding.
27
+ RequestAllOpenOrders = def_message 16
28
+
29
+ # Request that newly created TWS orders be implicitly associated with this client.
30
+ # When a new TWS order is created, the order will be associated with this client
31
+ # and automatically fed back through the OpenOrder and OrderStatus messages.
32
+ # It is a 'continuous' request such that it gets turned 'on' when called with a
33
+ # TRUE auto_bind parameter. When it's called with FALSE auto_bind, new TWS orders
34
+ # will not bind to this client going forward. Note that TWS orders can only be
35
+ # bound to clients with a client_id of 0. TODO: how to properly test this?
36
+ # data = { :auto_bind => boolean }
37
+ RequestAutoOpenOrders = def_message 15, :auto_bind
38
+
39
+ # Requests an XML document that describes the valid parameters that a scanner
40
+ # subscription can have (for outgoing RequestScannerSubscription message).
41
+ RequestScannerParameters = def_message 24
42
+
43
+ CancelNewsBulletins = def_message 13
44
+ RequestManagedAccounts = def_message 17
45
+ RequestCurrentTime = def_message 49
46
+ RequestGlobalCancel = def_message 58
47
+
48
+ ## Data format is: @data = { :id => ticker_id}
49
+ CancelMarketData = def_message 2
50
+ CancelMarketDepth = def_message 11
51
+ CancelScannerSubscription = def_message 23
52
+ CancelHistoricalData = def_message 25
53
+ CancelRealTimeBars = def_message 51
54
+
55
+ ## Data format is: @data = { :id => request_id }
56
+ CancelFundamentalData = def_message 53
57
+ CancelCalculateImpliedVolatility = CancelImpliedVolatility = def_message(56)
58
+ CancelCalculateOptionPrice = CancelOptionPrice = def_message(57)
59
+
60
+ ## Data format is: @data ={ :id => local_id of order to cancel }
61
+ CancelOrder = def_message 4
62
+
63
+ # Request the next valid ID that can be used when placing an order. Responds with
64
+ # NextValidId message, and the id returned is that next valid Id for orders.
65
+ # That ID will reflect any autobinding that has occurred (which generates new
66
+ # IDs and increments the next valid ID therein).
67
+ # @data = { :number of ids requested => int } NB: :number option is ignored by TWS!
68
+ RequestIds = def_message 8, [:number, 1]
69
+ # data = { :all_messages => boolean }
70
+ RequestNewsBulletins = def_message 12, :all_messages
71
+ # data = { :log_level => int }
72
+ SetServerLoglevel = def_message 14, :log_level
73
+ # data = { :fa_data_type => int }
74
+ RequestFA = def_message 18, :fa_data_type
75
+ # data = { :fa_data_type => int, :xml => String }
76
+ ReplaceFA = def_message 19, :fa_data_type, :xml
77
+ # data = { :market_data_type => int }
78
+
79
+ # @data = { :subscribe => boolean,
80
+ # :account_code => Advisor accounts only. Empty ('') for a standard account. }
81
+ RequestAccountUpdates = RequestAccountData = def_message([6, 2],
82
+ [:subscribe, true],
83
+ :account_code)
84
+
85
+ # data => { :id => request_id (int), :contract => Contract }
86
+ #
87
+ # Special case for options: "wildcards" in the Contract fields retrieve Option chains
88
+ # strike = 0 means all strikes
89
+ # right = "" meanns both call and put
90
+ # expiry = "" means all expiries
91
+ # expiry = "2013" means all expiries in 2013
92
+ # expiry = "201311" means all expiries in Nov 2013
93
+ # You'll get several ContractData (10) messages back if there is more than one match.
94
+ # When all the matches are delivered you'll get ContractDataEnd (52) message.
95
+ RequestContractDetails = RequestContractData =
96
+ def_message([9, 6],
97
+ [:contract, :serialize_short, [:con_id, :include_expired, :sec_id]])
98
+
99
+ # data = { :id => ticker_id (int), :contract => Contract, :num_rows => int }
100
+ RequestMarketDepth = def_message([10, 3],
101
+ [:contract, :serialize_short, []],
102
+ :num_rows)
103
+
104
+ # When this message is sent, TWS responds with ExecutionData messages, each
105
+ # containing the execution report that meets the specified criteria.
106
+ # @data={:id => int: :request_id,
107
+ # :client_id => int: Filter the results based on the clientId.
108
+ # :acct_code => Filter the results based on based on account code.
109
+ # Note: this is only relevant for Financial Advisor accts.
110
+ # :sec_type => Filter the results based on the order security type.
111
+ # :time => Filter the results based on execution reports received
112
+ # after the specified time - format "yyyymmdd-hh:mm:ss"
113
+ # :symbol => Filter the results based on the order symbol.
114
+ # :exchange => Filter the results based on the order exchange
115
+ # :side => Filter the results based on the order action: BUY/SELL/SSHORT
116
+ RequestExecutions = def_message([7, 3],
117
+ :client_id,
118
+ :acct_code,
119
+ :time, # Format "yyyymmdd-hh:mm:ss"
120
+ :symbol,
121
+ :sec_type,
122
+ :exchange,
123
+ :side)
124
+
125
+ # data = { :id => ticker_id (int),
126
+ # :contract => IB::Contract,
127
+ # :exercise_action => int, 1 = exercise, 2 = lapse
128
+ # :exercise_quantity => int, The number of contracts to be exercised
129
+ # :account => string,
130
+ # :override => int: Specifies whether your setting will override the
131
+ # system's natural action. For example, if your action
132
+ # is "exercise" and the option is not in-the-money, by
133
+ # natural action the option would not exercise. If you
134
+ # have override set to "yes" the natural action would be
135
+ # overridden and the out-of-the money option would be
136
+ # exercised. Values are:
137
+ # - 0 = do not override
138
+ # - 1 = override
139
+ ExerciseOptions = def_message(21,
140
+ [:contract, :serialize_short],
141
+ :exercise_action,
142
+ :exercise_quantity,
143
+ :account,
144
+ :override)
145
+
146
+ # @data={:id => int: ticker_id - Must be a unique value. When the market data
147
+ # returns, it will be identified by this tag,
148
+ # :contract => IB::Contract, requested contract.
149
+ # :tick_list => String: comma delimited list of requested tick groups:
150
+ # Group ID - Description - Requested Tick Types
151
+ # 100 - Option Volume (currently for stocks) - 29, 30
152
+ # 101 - Option Open Interest (currently for stocks) - 27, 28
153
+ # 104 - Historical Volatility (currently for stocks) - 23
154
+ # 106 - Option Implied Volatility (currently for stocks) - 24
155
+ # 162 - Index Future Premium - 31
156
+ # 165 - Miscellaneous Stats - 15, 16, 17, 18, 19, 20, 21
157
+ # 221 - Mark Price (used in TWS P&L computations) - 37
158
+ # 225 - Auction values (volume, price and imbalance) - 34, 35, 36
159
+ # 233 - RTVolume - 48
160
+ # 236 - Shortable - 46
161
+ # 256 - Inventory - ?
162
+ # 258 - Fundamental Ratios - 47
163
+ # 411 - Realtime Historical Volatility - 58
164
+ # :snapshot => bool: Check to return a single snapshot of market data and
165
+ # have the market data subscription canceled. Do not enter any
166
+ # :tick_list values if you use snapshot. }
167
+ RequestMarketData =
168
+ def_message([1, 9],
169
+ [:contract, :serialize_long, [:con_id]],
170
+ [:contract, :serialize_legs, []],
171
+ [:contract, :serialize_under_comp, []],
172
+ [:tick_list, lambda do |tick_list|
173
+ tick_list.is_a?(Array) ? tick_list.join(',') : (tick_list || '')
174
+ end, []],
175
+ [:snapshot, false])
176
+
177
+ # The API can receive frozen market data from Trader Workstation. Frozen market
178
+ # data is the last data recorded in our system. During normal trading hours,
179
+ # the API receives real-time market data. If you use this function, you are
180
+ # telling TWS to automatically switch to frozen market data AFTER the close.
181
+ # Then, before the opening of the next trading day, market data will automatically
182
+ # switch back to real-time market data.
183
+ # :market_data_type = 1 for real-time streaming, 2 for frozen market data
184
+ RequestMarketDataType =
185
+ def_message 59, [:market_data_type,
186
+ lambda { |type| MARKET_DATA_TYPES.invert[type] || type }, []]
187
+
188
+ # Send this message to receive Reuters global fundamental data. There must be
189
+ # a subscription to Reuters Fundamental set up in Account Management before
190
+ # you can receive this data.
191
+ # data = { :id => int: :request_id,
192
+ # :contract => Contract,
193
+ # :report_type => String: one of the following:
194
+ # 'estimates' - Estimates
195
+ # 'finstat' - Financial statements
196
+ # 'snapshot' - Summary }
197
+ RequestFundamentalData =
198
+ def_message(52,
199
+ [:contract, :serialize, [:primary_exchange]],
200
+ :report_type)
201
+
202
+ # data = { :request_id => int, :contract => Contract,
203
+ # :option_price => double, :under_price => double }
204
+ RequestCalculateImpliedVolatility = CalculateImpliedVolatility =
205
+ RequestImpliedVolatility =
206
+ def_message(54,
207
+ [:contract, :serialize_long, [:con_id]],
208
+ :option_price,
209
+ :under_price)
210
+
211
+ # data = { :request_id => int, :contract => Contract,
212
+ # :volatility => double, :under_price => double }
213
+ RequestCalculateOptionPrice = CalculateOptionPrice = RequestOptionPrice =
214
+ def_message(55,
215
+ [:contract, :serialize_long, [:con_id]],
216
+ :volatility,
217
+ :under_price)
218
+
219
+ # Start receiving market scanner results through the ScannerData messages.
220
+ # @data = { :id => ticker_id (int),
221
+ # :number_of_rows => int: number of rows of data to return for a query.
222
+ # :instrument => The instrument type for the scan. Values include
223
+ # 'STK', - US stocks
224
+ # 'STOCK.HK' - Asian stocks
225
+ # 'STOCK.EU' - European stocks
226
+ # :location_code => Legal Values include:
227
+ # - STK.US - US stocks
228
+ # - STK.US.MAJOR - US stocks (without pink sheet)
229
+ # - STK.US.MINOR - US stocks (only pink sheet)
230
+ # - STK.HK.SEHK - Hong Kong stocks
231
+ # - STK.HK.ASX - Australian Stocks
232
+ # - STK.EU - European stocks
233
+ # :scan_code => The type of the scan, such as HIGH_OPT_VOLUME_PUT_CALL_RATIO.
234
+ # :above_price => double: Only contracts with a price above this value.
235
+ # :below_price => double: Only contracts with a price below this value.
236
+ # :above_volume => int: Only contracts with a volume above this value.
237
+ # :market_cap_above => double: Only contracts with a market cap above this
238
+ # :market_cap_below => double: Only contracts with a market cap below this value.
239
+ # :moody_rating_above => Only contracts with a Moody rating above this value.
240
+ # :moody_rating_below => Only contracts with a Moody rating below this value.
241
+ # :sp_rating_above => Only contracts with an S&P rating above this value.
242
+ # :sp_rating_below => Only contracts with an S&P rating below this value.
243
+ # :maturity_date_above => Only contracts with a maturity date later than this
244
+ # :maturity_date_below => Only contracts with a maturity date earlier than this
245
+ # :coupon_rate_above => double: Only contracts with a coupon rate above this
246
+ # :coupon_rate_below => double: Only contracts with a coupon rate below this
247
+ # :exclude_convertible => Exclude convertible bonds.
248
+ # :scanner_setting_pairs => Used with the scan_code to help further narrow your query.
249
+ # Scanner Setting Pairs are delimited by slashes, making
250
+ # this parameter open ended. Example is "Annual,true" -
251
+ # when used with 'Top Option Implied Vol % Gainers' scan
252
+ # would return annualized volatilities.
253
+ # :average_option_volume_above => int: Only contracts with average volume above this
254
+ # :stock_type_filter => Valid values are:
255
+ # 'ALL' (excludes nothing)
256
+ # 'STOCK' (excludes ETFs)
257
+ # 'ETF' (includes ETFs) }
258
+ # ------------
259
+ # To learn all valid parameter values that a scanner subscription can have,
260
+ # first subscribe to ScannerParameters and send RequestScannerParameters message.
261
+ # Available scanner parameters values will be listed in received XML document.
262
+ RequestScannerSubscription =
263
+ def_message([22, 3],
264
+ [:number_of_rows, -1], # was: EOL,
265
+ :instrument,
266
+ :location_code,
267
+ :scan_code,
268
+ :above_price,
269
+ :below_price,
270
+ :above_volume,
271
+ :market_cap_above,
272
+ :market_cap_below,
273
+ :moody_rating_above,
274
+ :moody_rating_below,
275
+ :sp_rating_above,
276
+ :sp_rating_below,
277
+ :maturity_date_above,
278
+ :maturity_date_below,
279
+ :coupon_rate_above,
280
+ :coupon_rate_below,
281
+ :exclude_convertible,
282
+ :average_option_volume_above, # ?
283
+ :scanner_setting_pairs,
284
+ :stock_type_filter)
285
+
286
+ require 'ib/messages/outgoing/place_order'
287
+ require 'ib/messages/outgoing/bar_requests'
288
+
289
+ end # module Outgoing
290
+ end # module Messages
291
+ end # module IB
292
+
293
+ __END__
294
+
295
+ // outgoing msg id's
296
+ private static final int REQ_MKT_DATA = 1;
297
+ private static final int CANCEL_MKT_DATA = 2;
298
+ private static final int PLACE_ORDER = 3;
299
+ private static final int CANCEL_ORDER = 4;
300
+ private static final int REQ_OPEN_ORDERS = 5;
301
+ private static final int REQ_ACCOUNT_DATA = 6;
302
+ private static final int REQ_EXECUTIONS = 7;
303
+ private static final int REQ_IDS = 8;
304
+ private static final int REQ_CONTRACT_DATA = 9;
305
+ private static final int REQ_MKT_DEPTH = 10;
306
+ private static final int CANCEL_MKT_DEPTH = 11;
307
+ private static final int REQ_NEWS_BULLETINS = 12;
308
+ private static final int CANCEL_NEWS_BULLETINS = 13;
309
+ private static final int SET_SERVER_LOGLEVEL = 14;
310
+ private static final int REQ_AUTO_OPEN_ORDERS = 15;
311
+ private static final int REQ_ALL_OPEN_ORDERS = 16;
312
+ private static final int REQ_MANAGED_ACCTS = 17;
313
+ private static final int REQ_FA = 18;
314
+ private static final int REPLACE_FA = 19;
315
+ private static final int REQ_HISTORICAL_DATA = 20;
316
+ private static final int EXERCISE_OPTIONS = 21;
317
+ private static final int REQ_SCANNER_SUBSCRIPTION = 22;
318
+ private static final int CANCEL_SCANNER_SUBSCRIPTION = 23;
319
+ private static final int REQ_SCANNER_PARAMETERS = 24;
320
+ private static final int CANCEL_HISTORICAL_DATA = 25;
321
+ private static final int REQ_CURRENT_TIME = 49;
322
+ private static final int REQ_REAL_TIME_BARS = 50;
323
+ private static final int CANCEL_REAL_TIME_BARS = 51;
324
+ private static final int REQ_FUNDAMENTAL_DATA = 52;
325
+ private static final int CANCEL_FUNDAMENTAL_DATA = 53;
326
+ private static final int REQ_CALC_IMPLIED_VOLAT = 54;
327
+ private static final int REQ_CALC_OPTION_PRICE = 55;
328
+ private static final int CANCEL_CALC_IMPLIED_VOLAT = 56;
329
+ private static final int CANCEL_CALC_OPTION_PRICE = 57;
330
+ private static final int REQ_GLOBAL_CANCEL = 58;
331
+ private static final int REQ_MARKET_DATA_TYPE = 59;