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,34 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # Called Error in Java code, but in fact this type of messages also
6
+ # deliver system alerts and additional (non-error) info from TWS.
7
+ ErrorMessage = Error = Alert = def_message([4, 2],
8
+ [:error_id, :int],
9
+ [:code, :int],
10
+ [:message, :string])
11
+ class Alert
12
+ # Is it an Error message?
13
+ def error?
14
+ code < 1000
15
+ end
16
+
17
+ # Is it a System message?
18
+ def system?
19
+ code > 1000 && code < 2000
20
+ end
21
+
22
+ # Is it a Warning message?
23
+ def warning?
24
+ code > 2000
25
+ end
26
+
27
+ def to_human
28
+ "TWS #{ error? ? 'Error' : system? ? 'System' : 'Warning'} #{code}: #{message}"
29
+ end
30
+ end # class Alert
31
+
32
+ end # module Incoming
33
+ end # module Messages
34
+ end # module IB
@@ -0,0 +1,102 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+ module ContractAccessors
5
+
6
+ end
7
+
8
+ ContractDetails = ContractData =
9
+ def_message([10, [6, 8]],
10
+ [:request_id, :int], # request id
11
+ [:contract, :symbol, :string],
12
+ [:contract, :sec_type, :string],
13
+ [:contract, :expiry, :string],
14
+ [:contract, :strike, :decimal],
15
+ [:contract, :right, :string],
16
+ [:contract, :exchange, :string],
17
+ [:contract, :currency, :string],
18
+ [:contract, :local_symbol, :string],
19
+
20
+ [:contract_detail, :market_name, :string], # extended
21
+ [:contract_detail, :trading_class, :string],
22
+ [:contract, :con_id, :int],
23
+ [:contract_detail, :min_tick, :decimal],
24
+ [:contract, :multiplier, :string],
25
+ [:contract_detail, :order_types, :string],
26
+ [:contract_detail, :valid_exchanges, :string],
27
+ [:contract_detail, :price_magnifier, :int],
28
+ [:contract_detail, :under_con_id, :int],
29
+ [:contract_detail, :long_name, :string],
30
+ [:contract, :primary_exchange, :string],
31
+ [:contract_detail, :contract_month, :string],
32
+ [:contract_detail, :industry, :string],
33
+ [:contract_detail, :category, :string],
34
+ [:contract_detail, :subcategory, :string],
35
+ [:contract_detail, :time_zone, :string],
36
+ [:contract_detail, :trading_hours, :string],
37
+ [:contract_detail, :liquid_hours, :string],
38
+ [:contract_detail, :ev_rule, :decimal],
39
+ [:contract_detail, :ev_multipler, :string],
40
+ [:sec_id_list_count, :int])
41
+
42
+
43
+ class ContractData
44
+
45
+ def contract
46
+ @contract = IB::Contract.build @data[:contract].
47
+ merge(:contract_detail => contract_detail)
48
+ end
49
+
50
+ def contract_detail
51
+ @contract_detail = IB::ContractDetail.new @data[:contract_detail]
52
+ end
53
+
54
+ alias contract_details contract_detail
55
+
56
+ def load
57
+ super
58
+
59
+ @data[:contract_detail][:sec_id_list] ||= HashWithIndifferentAccess.new
60
+ @data[:sec_id_list_count].times do
61
+ @data[:contract_detail][:sec_id_list][socket.read_string] = socket.read_string
62
+ end
63
+ end
64
+
65
+ end # ContractData
66
+
67
+ BondContractData =
68
+ def_message [18, [4, 6]], ContractData,
69
+ [:request_id, :int],
70
+ [:contract, :symbol, :string],
71
+ [:contract, :sec_type, :string],
72
+ [:contract_detail, :cusip, :string],
73
+ [:contract_detail, :coupon, :decimal],
74
+ [:contract_detail, :maturity, :string],
75
+ [:contract_detail, :issue_date, :string],
76
+ [:contract_detail, :ratings, :string],
77
+ [:contract_detail, :bond_type, :string],
78
+ [:contract_detail, :coupon_type, :string],
79
+ [:contract_detail, :convertible, :boolean],
80
+ [:contract_detail, :callable, :boolean],
81
+ [:contract_detail, :puttable, :boolean],
82
+ [:contract_detail, :desc_append, :string],
83
+ [:contract, :exchange, :string],
84
+ [:contract, :currency, :string],
85
+ [:contract_detail, :market_name, :string], # extended
86
+ [:contract_detail, :trading_class, :string],
87
+ [:contract, :con_id, :int],
88
+ [:contract_detail, :min_tick, :decimal],
89
+ [:contract_detail, :order_types, :string],
90
+ [:contract_detail, :valid_exchanges, :string],
91
+ [:contract_detail, :valid_next_option_date, :string],
92
+ [:contract_detail, :valid_next_option_type, :string],
93
+ [:contract_detail, :valid_next_option_partial, :string],
94
+ [:contract_detail, :notes, :string],
95
+ [:contract_detail, :long_name, :string],
96
+ [:contract_detail, :ev_rule, :decimal],
97
+ [:contract_detail, :ev_multipler, :string],
98
+ [:sec_id_list_count, :int]
99
+
100
+ end # module Incoming
101
+ end # module Messages
102
+ end # module IB
@@ -0,0 +1,23 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # The server sends this message upon accepting a Delta-Neutral DN RFQ
6
+ # - see API Reference p. 26
7
+ DeltaNeutralValidation = def_message 56,
8
+ [:request_id, :int],
9
+ [:underlying, :con_id, :int],
10
+ [:underlying, :delta, :decimal],
11
+ [:underlying, :price, :decimal]
12
+ class DeltaNeutralValidation
13
+ def underlying
14
+ @underlying = IB::Underlying.new @data[:underlying]
15
+ end
16
+
17
+ alias under_comp underlying
18
+
19
+ end # DeltaNeutralValidation
20
+
21
+ end # module Incoming
22
+ end # module Messages
23
+ end # module IB
@@ -0,0 +1,54 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ ExecutionData =
6
+ def_message [11, [8, 9]],
7
+ # The reqID that was specified previously in the call to reqExecution()
8
+ [:request_id, :int],
9
+ [:execution, :local_id, :int],
10
+ [:contract, :con_id, :int],
11
+ [:contract, :symbol, :string],
12
+ [:contract, :sec_type, :string],
13
+ [:contract, :expiry, :string],
14
+ [:contract, :strike, :decimal],
15
+ [:contract, :right, :string],
16
+ [:contract, :multiplier, :string],
17
+ [:contract, :exchange, :string],
18
+ [:contract, :currency, :string],
19
+ [:contract, :local_symbol, :string],
20
+
21
+ [:execution, :exec_id, :string], # Weird format
22
+ [:execution, :time, :string],
23
+ [:execution, :account_name, :string],
24
+ [:execution, :exchange, :string],
25
+ [:execution, :side, :string],
26
+ [:execution, :quantity, :int],
27
+ [:execution, :price, :decimal],
28
+ [:execution, :perm_id, :int],
29
+ [:execution, :client_id, :int],
30
+ [:execution, :liquidation, :int],
31
+ [:execution, :cumulative_quantity, :int],
32
+ [:execution, :average_price, :decimal],
33
+ [:execution, :order_ref, :string],
34
+ [:execution, :ev_rule, :string],
35
+ [:execution, :ev_multiplier, :decimal]
36
+
37
+ class ExecutionData
38
+
39
+ def contract
40
+ @contract = IB::Contract.build @data[:contract]
41
+ end
42
+
43
+ def execution
44
+ @execution = IB::Execution.new @data[:execution]
45
+ end
46
+
47
+ def to_human
48
+ "<ExecutionData #{request_id}: #{contract.to_human}, #{execution}>"
49
+ end
50
+
51
+ end # ExecutionData
52
+ end # module Incoming
53
+ end # module Messages
54
+ end # module IB
@@ -0,0 +1,55 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # HistoricalData contains following @data:
6
+ # General:
7
+ # :request_id - The ID of the request to which this is responding
8
+ # :count - Number of Historical data points returned (size of :results).
9
+ # :results - an Array of Historical Data Bars
10
+ # :start_date - beginning of returned Historical data period
11
+ # :end_date - end of returned Historical data period
12
+ # Each returned Bar in @data[:results] Array contains this data:
13
+ # :date - The date-time stamp of the start of the bar. The format is
14
+ # determined by the RequestHistoricalData formatDate parameter.
15
+ # :open - The bar opening price.
16
+ # :high - The high price during the time covered by the bar.
17
+ # :low - The low price during the time covered by the bar.
18
+ # :close - The bar closing price.
19
+ # :volume - The volume during the time covered by the bar.
20
+ # :trades - When TRADES historical data is returned, represents number of trades
21
+ # that occurred during the time period the bar covers
22
+ # :wap - The weighted average price during the time covered by the bar.
23
+ # :has_gaps - Whether or not there are gaps in the data.
24
+
25
+ HistoricalData = def_message [17, 3],
26
+ [:request_id, :int],
27
+ [:start_date, :string],
28
+ [:end_date, :string],
29
+ [:count, :int]
30
+ class HistoricalData
31
+ attr_accessor :results
32
+
33
+ def load
34
+ super
35
+
36
+ @results = Array.new(@data[:count]) do |_|
37
+ IB::Bar.new :time => socket.read_string,
38
+ :open => socket.read_decimal,
39
+ :high => socket.read_decimal,
40
+ :low => socket.read_decimal,
41
+ :close => socket.read_decimal,
42
+ :volume => socket.read_int,
43
+ :wap => socket.read_decimal,
44
+ :has_gaps => socket.read_string,
45
+ :trades => socket.read_int
46
+ end
47
+ end
48
+
49
+ def to_human
50
+ "<HistoricalData: #{request_id}, #{count} items, #{start_date} to #{end_date}>"
51
+ end
52
+ end # HistoricalData
53
+ end # module Incoming
54
+ end # module Messages
55
+ end # module IB
@@ -0,0 +1,44 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ MarketDepth =
6
+ def_message 12, [:request_id, :int],
7
+ [:position, :int], # The row Id of this market depth entry.
8
+ [:operation, :int], # How it should be applied to the market depth:
9
+ # 0 = insert this new order into the row identified by :position
10
+ # 1 = update the existing order in the row identified by :position
11
+ # 2 = delete the existing order at the row identified by :position
12
+ [:side, :int], # side of the book: 0 = ask, 1 = bid
13
+ [:price, :decimal],
14
+ [:size, :int]
15
+
16
+ class MarketDepth
17
+ def side
18
+ @data[:side] == 0 ? :ask : :bid
19
+ end
20
+
21
+ def operation
22
+ @data[:operation] == 0 ? :insert : @data[:operation] == 1 ? :update : :delete
23
+ end
24
+
25
+ def to_human
26
+ "<#{self.message_type}: #{operation} #{side} @ "+
27
+ "#{position} = #{price} x #{size}>"
28
+ end
29
+ end
30
+
31
+ MarketDepthL2 =
32
+ def_message 13, MarketDepth, # Fields descriptions - see above
33
+ [:request_id, :int],
34
+ [:position, :int],
35
+ [:market_maker, :string], # The exchange hosting this order.
36
+ [:operation, :int],
37
+ [:side, :int],
38
+ [:price, :decimal],
39
+ [:size, :int]
40
+
41
+
42
+ end # module Incoming
43
+ end # module Messages
44
+ end # module IB
@@ -0,0 +1,18 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # This message is always sent by TWS automatically at connect.
6
+ # The IB::Connection class subscribes to it automatically and stores
7
+ # the order id in its @next_local_id attribute.
8
+ NextValidID = NextValidId = def_message(9, [:local_id, :int])
9
+
10
+ class NextValidId
11
+
12
+ # Legacy accessor
13
+ alias order_id local_id
14
+
15
+ end # class NextValidId
16
+ end # module Incoming
17
+ end # module Messages
18
+ end # module IB
@@ -0,0 +1,232 @@
1
+ module IB
2
+ module Messages
3
+ module Incoming
4
+
5
+ # OpenOrder is the longest message with complex processing logics
6
+ OpenOrder =
7
+ def_message [5, 30],
8
+ [:order, :local_id, :int],
9
+
10
+ [:contract, :con_id, :int],
11
+ [:contract, :symbol, :string],
12
+ [:contract, :sec_type, :string],
13
+ [:contract, :expiry, :string],
14
+ [:contract, :strike, :decimal],
15
+ [:contract, :right, :string],
16
+ [:contract, :exchange, :string],
17
+ [:contract, :currency, :string],
18
+ [:contract, :local_symbol, :string],
19
+
20
+ [:order, :action, :string],
21
+ [:order, :total_quantity, :int],
22
+ [:order, :order_type, :string],
23
+ [:order, :limit_price, :decimal_max],
24
+ [:order, :aux_price, :decimal_max],
25
+ [:order, :tif, :string],
26
+ [:order, :oca_group, :string],
27
+ [:order, :account, :string],
28
+ [:order, :open_close, :string],
29
+ [:order, :origin, :int],
30
+ [:order, :order_ref, :string],
31
+ [:order, :client_id, :int],
32
+ [:order, :perm_id, :int],
33
+ [:order, :outside_rth, :boolean], # (@socket.read_int == 1)
34
+ [:order, :hidden, :boolean], # (@socket.read_int == 1)
35
+ [:order, :discretionary_amount, :decimal],
36
+ [:order, :good_after_time, :string],
37
+ [:shares_allocation, :string], # deprecated! field
38
+
39
+ [:order, :fa_group, :string],
40
+ [:order, :fa_method, :string],
41
+ [:order, :fa_percentage, :string],
42
+ [:order, :fa_profile, :string],
43
+ [:order, :good_till_date, :string],
44
+ [:order, :rule_80a, :string],
45
+ [:order, :percent_offset, :decimal_max],
46
+ [:order, :settling_firm, :string],
47
+ [:order, :short_sale_slot, :int],
48
+ [:order, :designated_location, :string],
49
+ [:order, :exempt_code, :int], # skipped in ver 51?
50
+ [:order, :auction_strategy, :int],
51
+ [:order, :starting_price, :decimal_max],
52
+ [:order, :stock_ref_price, :decimal_max],
53
+ [:order, :delta, :decimal_max],
54
+ [:order, :stock_range_lower, :decimal_max],
55
+ [:order, :stock_range_upper, :decimal_max],
56
+ [:order, :display_size, :int],
57
+ #@order.rth_only = @socket.read_boolean
58
+ [:order, :block_order, :boolean],
59
+ [:order, :sweep_to_fill, :boolean],
60
+ [:order, :all_or_none, :boolean],
61
+ [:order, :min_quantity, :int_max],
62
+ [:order, :oca_type, :int],
63
+ [:order, :etrade_only, :boolean],
64
+ [:order, :firm_quote_only, :boolean],
65
+ [:order, :nbbo_price_cap, :decimal_max],
66
+ [:order, :parent_id, :int],
67
+ [:order, :trigger_method, :int],
68
+ [:order, :volatility, :decimal_max],
69
+ [:order, :volatility_type, :int],
70
+ [:order, :delta_neutral_order_type, :string],
71
+ [:order, :delta_neutral_aux_price, :decimal_max]
72
+
73
+ class OpenOrder
74
+
75
+ # Accessors to make OpenOrder API-compatible with OrderStatus message
76
+
77
+ def client_id
78
+ order.client_id
79
+ end
80
+
81
+ def parent_id
82
+ order.parent_id
83
+ end
84
+
85
+ def perm_id
86
+ order.perm_id
87
+ end
88
+
89
+ def local_id
90
+ order.local_id
91
+ end
92
+
93
+ alias order_id local_id
94
+
95
+ def status
96
+ order.status
97
+ end
98
+
99
+ # Object accessors
100
+
101
+ def order
102
+ @order ||= IB::Order.new @data[:order].merge(:order_state => order_state)
103
+ end
104
+
105
+ def order_state
106
+ @order_state ||= IB::OrderState.new(
107
+ @data[:order_state].merge(
108
+ :local_id => @data[:order][:local_id],
109
+ :perm_id => @data[:order][:perm_id],
110
+ :parent_id => @data[:order][:parent_id],
111
+ :client_id => @data[:order][:client_id]))
112
+ end
113
+
114
+ def contract
115
+ @contract ||= IB::Contract.build(
116
+ @data[:contract].merge(:underlying => underlying)
117
+ )
118
+ end
119
+
120
+ def underlying
121
+ @underlying = @data[:underlying_present] ? IB::Underlying.new(@data[:underlying]) : nil
122
+ end
123
+
124
+ alias under_comp underlying
125
+
126
+ def load
127
+ super
128
+
129
+ load_map [proc { | | filled?(@data[:order][:delta_neutral_order_type]) },
130
+ # As of client v.52, we may receive delta... params in openOrder
131
+ [:order, :delta_neutral_con_id, :int],
132
+ [:order, :delta_neutral_settling_firm, :string],
133
+ [:order, :delta_neutral_clearing_account, :string],
134
+ [:order, :delta_neutral_clearing_intent, :string]],
135
+
136
+ [:order, :continuous_update, :int],
137
+ [:order, :reference_price_type, :int],
138
+ [:order, :trail_stop_price, :decimal_max],
139
+ [:order, :trailing_percent, :decimal_max],
140
+ [:order, :basis_points, :decimal_max],
141
+ [:order, :basis_points_type, :int_max],
142
+ [:contract, :legs_description, :string],
143
+
144
+ # As of client v.55, we receive in OpenOrder for Combos:
145
+ # Contract.orderComboLegs Array
146
+ # Order.leg_prices Array
147
+ [:contract, :legs, :array, proc do |_|
148
+ IB::ComboLeg.new :con_id => socket.read_int,
149
+ :ratio => socket.read_int,
150
+ :action => socket.read_string,
151
+ :exchange => socket.read_string,
152
+ :open_close => socket.read_int,
153
+ :short_sale_slot => socket.read_int,
154
+ :designated_location => socket.read_string,
155
+ :exempt_code => socket.read_int
156
+ end],
157
+ [:order, :leg_prices, :array, proc { |_| socket.read_decimal_max }],
158
+ [:smart_combo_routing_params, :hash],
159
+
160
+ [:order, :scale_init_level_size, :int_max],
161
+ [:order, :scale_subs_level_size, :int_max],
162
+
163
+ [:order, :scale_price_increment, :decimal_max],
164
+ [proc { | | filled?(@data[:order][:scale_price_increment]) },
165
+ # As of client v.54, we may receive scale order fields
166
+ [:order, :scale_price_adjust_value, :decimal_max],
167
+ [:order, :scale_price_adjust_interval, :int_max],
168
+ [:order, :scale_profit_offset, :decimal_max],
169
+ [:order, :scale_auto_reset, :boolean],
170
+ [:order, :scale_init_position, :int_max],
171
+ [:order, :scale_init_fill_qty, :decimal_max],
172
+ [:order, :scale_random_percent, :boolean]
173
+ ],
174
+
175
+ [:order, :hedge_type, :string],
176
+ [proc { | | filled?(@data[:order][:hedge_type]) },
177
+ # As of client v.49/50, we can receive hedgeType, hedgeParam
178
+ [:order, :hedge_param, :string]
179
+ ],
180
+
181
+ [:order, :opt_out_smart_routing, :boolean],
182
+ [:order, :clearing_account, :string],
183
+ [:order, :clearing_intent, :string],
184
+ [:order, :not_held, :boolean],
185
+
186
+ [:underlying_present, :boolean],
187
+ [proc { | | filled?(@data[:underlying_present]) },
188
+ [:underlying, :con_id, :int],
189
+ [:underlying, :delta, :decimal],
190
+ [:underlying, :price, :decimal]
191
+ ],
192
+
193
+ # TODO: Test Order with algo_params, scale and legs!
194
+ [:order, :algo_strategy, :string],
195
+ [proc { | | filled?(@data[:order][:algo_strategy]) },
196
+ [:order, :algo_params, :hash]
197
+ ],
198
+
199
+ [:order, :what_if, :boolean],
200
+
201
+ [:order_state, :status, :string],
202
+ # IB uses weird String with Java Double.MAX_VALUE to indicate no value here
203
+ [:order_state, :init_margin, :decimal_max], # :string],
204
+ [:order_state, :maint_margin, :decimal_max], # :string],
205
+ [:order_state, :equity_with_loan, :decimal_max], # :string],
206
+ [:order_state, :commission, :decimal_max], # May be nil!
207
+ [:order_state, :min_commission, :decimal_max], # May be nil!
208
+ [:order_state, :max_commission, :decimal_max], # May be nil!
209
+ [:order_state, :commission_currency, :string],
210
+ [:order_state, :warning_text, :string]
211
+ end
212
+
213
+ # Check if given value was set by TWS to something vaguely "positive"
214
+ def filled? value
215
+ case value
216
+ when String
217
+ !value.empty?
218
+ when Float, Integer
219
+ value > 0
220
+ else
221
+ !!value # to_bool
222
+ end
223
+ end
224
+
225
+ def to_human
226
+ "<OpenOrder: #{contract.to_human} #{order.to_human}>"
227
+ end
228
+
229
+ end # class OpenOrder
230
+ end # module Incoming
231
+ end # module Messages
232
+ end # module IB