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.
- checksums.yaml +7 -0
- data/lib/ib-api.rb +10 -0
- data/lib/ib/base.rb +99 -0
- data/lib/ib/base_properties.rb +154 -0
- data/lib/ib/connection.rb +327 -0
- data/lib/ib/constants.rb +334 -0
- data/lib/ib/db.rb +29 -0
- data/lib/ib/engine.rb +35 -0
- data/lib/ib/errors.rb +40 -0
- data/lib/ib/extensions.rb +72 -0
- data/lib/ib/flex.rb +106 -0
- data/lib/ib/logger.rb +25 -0
- data/lib/ib/messages.rb +88 -0
- data/lib/ib/messages/abstract_message.rb +89 -0
- data/lib/ib/messages/incoming.rb +134 -0
- data/lib/ib/messages/incoming/abstract_message.rb +99 -0
- data/lib/ib/messages/incoming/alert.rb +34 -0
- data/lib/ib/messages/incoming/contract_data.rb +102 -0
- data/lib/ib/messages/incoming/delta_neutral_validation.rb +23 -0
- data/lib/ib/messages/incoming/execution_data.rb +54 -0
- data/lib/ib/messages/incoming/historical_data.rb +55 -0
- data/lib/ib/messages/incoming/market_depths.rb +44 -0
- data/lib/ib/messages/incoming/next_valid_id.rb +18 -0
- data/lib/ib/messages/incoming/open_order.rb +232 -0
- data/lib/ib/messages/incoming/order_status.rb +81 -0
- data/lib/ib/messages/incoming/portfolio_value.rb +39 -0
- data/lib/ib/messages/incoming/real_time_bar.rb +32 -0
- data/lib/ib/messages/incoming/scanner_data.rb +53 -0
- data/lib/ib/messages/incoming/ticks.rb +131 -0
- data/lib/ib/messages/outgoing.rb +331 -0
- data/lib/ib/messages/outgoing/abstract_message.rb +73 -0
- data/lib/ib/messages/outgoing/bar_requests.rb +189 -0
- data/lib/ib/messages/outgoing/place_order.rb +141 -0
- data/lib/ib/model.rb +6 -0
- data/lib/ib/models.rb +10 -0
- data/lib/ib/requires.rb +9 -0
- data/lib/ib/socket.rb +81 -0
- data/lib/ib/symbols.rb +35 -0
- data/lib/ib/symbols/bonds.rb +28 -0
- data/lib/ib/symbols/forex.rb +41 -0
- data/lib/ib/symbols/futures.rb +117 -0
- data/lib/ib/symbols/options.rb +39 -0
- data/lib/ib/symbols/stocks.rb +37 -0
- data/lib/ib/version.rb +6 -0
- data/lib/models/ib/bag.rb +51 -0
- data/lib/models/ib/bar.rb +45 -0
- data/lib/models/ib/combo_leg.rb +103 -0
- data/lib/models/ib/contract.rb +292 -0
- data/lib/models/ib/contract_detail.rb +89 -0
- data/lib/models/ib/execution.rb +65 -0
- data/lib/models/ib/option.rb +60 -0
- data/lib/models/ib/order.rb +391 -0
- data/lib/models/ib/order_state.rb +128 -0
- data/lib/models/ib/underlying.rb +34 -0
- metadata +96 -0
data/lib/ib/constants.rb
ADDED
@@ -0,0 +1,334 @@
|
|
1
|
+
module IB
|
2
|
+
### Widely used TWS constants:
|
3
|
+
|
4
|
+
EOL = "\0"
|
5
|
+
|
6
|
+
# Enumeration of bar size types for convenience.
|
7
|
+
# Bar sizes less than 30 seconds do not work for some securities.
|
8
|
+
BAR_SIZES = {'1 sec' => :sec1,
|
9
|
+
'5 secs' => :sec5,
|
10
|
+
'15 secs' =>:sec15,
|
11
|
+
'30 secs' =>:sec30,
|
12
|
+
'1 min' => :min1,
|
13
|
+
'2 mins' => :min2,
|
14
|
+
'3 mins' => :min3,
|
15
|
+
'5 mins' => :min5,
|
16
|
+
'15 mins' =>:min15,
|
17
|
+
'30 mins' =>:min30,
|
18
|
+
'1 hour' =>:hour1,
|
19
|
+
'1 day' => :day1
|
20
|
+
}.freeze
|
21
|
+
|
22
|
+
# Enumeration of data types.
|
23
|
+
# Determines the nature of data being extracted. Valid values:
|
24
|
+
DATA_TYPES = {'TRADES' => :trades,
|
25
|
+
'MIDPOINT' => :midpoint,
|
26
|
+
'BID' => :bid,
|
27
|
+
'ASK' => :ask,
|
28
|
+
'BID_ASK' => :bid_ask,
|
29
|
+
'HISTORICAL_VOLATILITY' => :historical_volatility,
|
30
|
+
'OPTION_IMPLIED_VOLATILITY' => :option_implied_volatility,
|
31
|
+
'OPTION_VOLUME' => :option_volume,
|
32
|
+
'OPTION_OPEN_INTEREST' => :option_open_interest
|
33
|
+
}.freeze
|
34
|
+
|
35
|
+
### These values are typically received from TWS in incoming messages
|
36
|
+
|
37
|
+
# Tick types as received in TickPrice and TickSize messages (enumeration)
|
38
|
+
TICK_TYPES = {
|
39
|
+
# int id => :Description # Corresponding API Event/Function/Method
|
40
|
+
0 => :bid_size, # tickSize()
|
41
|
+
1 => :bid_price, # tickPrice()
|
42
|
+
2 => :ask_price, # tickPrice()
|
43
|
+
3 => :ask_size, # tickSize()
|
44
|
+
4 => :last_price, # tickPrice()
|
45
|
+
5 => :last_size, # tickSize()
|
46
|
+
6 => :high, # tickPrice()
|
47
|
+
7 => :low, # tickPrice()
|
48
|
+
8 => :volume, # tickSize()
|
49
|
+
9 => :close_price, # tickPrice()
|
50
|
+
10 => :bid_option, # tickOptionComputation() See Note 1 below
|
51
|
+
11 => :ask_option, # tickOptionComputation() See => :Note 1 below
|
52
|
+
12 => :last_option, # tickOptionComputation() See Note 1 below
|
53
|
+
13 => :model_option, # tickOptionComputation() See Note 1 below
|
54
|
+
14 => :open_tick, # tickPrice()
|
55
|
+
15 => :low_13_week, # tickPrice()
|
56
|
+
16 => :high_13_week, # tickPrice()
|
57
|
+
17 => :low_26_week, # tickPrice()
|
58
|
+
18 => :high_26_week, # tickPrice()
|
59
|
+
19 => :low_52_week, # tickPrice()
|
60
|
+
20 => :high_52_week, # tickPrice()
|
61
|
+
21 => :avg_volume, # tickSize()
|
62
|
+
22 => :open_interest, # tickSize()
|
63
|
+
23 => :option_historical_vol, # tickGeneric()
|
64
|
+
24 => :option_implied_vol, # tickGeneric()
|
65
|
+
25 => :option_bid_exch, # not USED
|
66
|
+
26 => :option_ask_exch, # not USED
|
67
|
+
27 => :option_call_open_interest, # tickSize()
|
68
|
+
28 => :option_put_open_interest, # tickSize()
|
69
|
+
29 => :option_call_volume, # tickSize()
|
70
|
+
30 => :option_put_volume, # tickSize()
|
71
|
+
31 => :index_future_premium, # tickGeneric()
|
72
|
+
32 => :bid_exch, # tickString()
|
73
|
+
33 => :ask_exch, # tickString()
|
74
|
+
34 => :auction_volume, # not USED
|
75
|
+
35 => :auction_price, # not USED
|
76
|
+
36 => :auction_imbalance, # not USED
|
77
|
+
37 => :mark_price, # tickPrice()
|
78
|
+
38 => :bid_efp_computation, # tickEFP()
|
79
|
+
39 => :ask_efp_computation, # tickEFP()
|
80
|
+
40 => :last_efp_computation, # tickEFP()
|
81
|
+
41 => :open_efp_computation, # tickEFP()
|
82
|
+
42 => :high_efp_computation, # tickEFP()
|
83
|
+
43 => :low_efp_computation, # tickEFP()
|
84
|
+
44 => :close_efp_computation, # tickEFP()
|
85
|
+
45 => :last_timestamp, # tickString()
|
86
|
+
46 => :shortable, # tickGeneric()
|
87
|
+
47 => :fundamental_ratios, # tickString()
|
88
|
+
48 => :rt_volume, # tickGeneric()
|
89
|
+
49 => :halted, # see Note 2 below.
|
90
|
+
50 => :bid_yield, # tickPrice() See Note 3 below
|
91
|
+
51 => :ask_yield, # tickPrice() See Note 3 below
|
92
|
+
52 => :last_yield, # tickPrice() See Note 3 below
|
93
|
+
53 => :cust_option_computation, # tickOptionComputation()
|
94
|
+
54 => :trade_count, # tickGeneric()
|
95
|
+
55 => :trade_rate, # tickGeneric()
|
96
|
+
56 => :volume_rate, # tickGeneric()
|
97
|
+
57 => :last_rth_trade, # ?
|
98
|
+
# Note 1: Tick types BID_OPTION, ASK_OPTION, LAST_OPTION, and MODEL_OPTION return
|
99
|
+
# all Greeks (delta, gamma, vega, theta), the underlying price and the
|
100
|
+
# stock and option reference price when requested.
|
101
|
+
# MODEL_OPTION also returns model implied volatility.
|
102
|
+
# Note 2: When trading is halted for a contract, TWS receives a special tick:
|
103
|
+
# haltedLast=1. When trading is resumed, TWS receives haltedLast=0.
|
104
|
+
# A tick type, HALTED, tick ID= 49, is now available in regular market
|
105
|
+
# data via the API to indicate this halted state. Possible values for
|
106
|
+
# this new tick type are: 0 = Not halted, 1 = Halted.
|
107
|
+
# Note 3: Applies to bond contracts only.
|
108
|
+
}
|
109
|
+
|
110
|
+
# Financial Advisor types (FaMsgTypeName)
|
111
|
+
FA_TYPES = {
|
112
|
+
1 => :groups,
|
113
|
+
2 => :profiles,
|
114
|
+
3 => :aliases}.freeze
|
115
|
+
|
116
|
+
# Received in new MarketDataType (58 incoming) message
|
117
|
+
MARKET_DATA_TYPES = {
|
118
|
+
0 => :unknown,
|
119
|
+
1 => :real_time,
|
120
|
+
2 => :frozen,
|
121
|
+
}
|
122
|
+
|
123
|
+
# Market depth messages contain these "operation" codes to tell you what to do with the data.
|
124
|
+
# See also http://www.interactivebrokers.com/php/apiUsersGuide/apiguide/java/updatemktdepth.htm
|
125
|
+
MARKET_DEPTH_OPERATIONS = {
|
126
|
+
0 => :insert, # New order, insert into the row identified by :position
|
127
|
+
1 => :update, # Update the existing order at the row identified by :position
|
128
|
+
2 => :delete # Delete the existing order at the row identified by :position
|
129
|
+
}.freeze
|
130
|
+
|
131
|
+
MARKET_DEPTH_SIDES = {
|
132
|
+
0 => :ask,
|
133
|
+
1 => :bid
|
134
|
+
}.freeze
|
135
|
+
|
136
|
+
ORDER_TYPES =
|
137
|
+
{'LMT' => :limit, # Limit Order
|
138
|
+
'LIT' => :limit_if_touched, # Limit if Touched
|
139
|
+
'LOC' => :limit_on_close, # Limit-on-Close LMTCLS ?
|
140
|
+
'LOO' => :limit_on_open, # Limit-on-Open
|
141
|
+
'MKT' => :market, # Market
|
142
|
+
'MIT' => :market_if_touched, # Market-if-Touched
|
143
|
+
'MOC' => :market_on_close, # Market-on-Close MKTCLSL ?
|
144
|
+
'MOO' => :market_on_open, # Market-on-Open
|
145
|
+
'MTL' => :market_to_limit, # Market-to-Limit
|
146
|
+
'MKTPRT' => :market_protected, # Market with Protection
|
147
|
+
'QUOTE' => :request_for_quote, # Request for Quote
|
148
|
+
'STP' => :stop, # Stop
|
149
|
+
'STPLMT' => :stop_limit, # Stop Limit
|
150
|
+
'TRAIL' => :trailing_stop, # Trailing Stop
|
151
|
+
'TRAIL LIMIT' => :trailing_limit, # Trailing Stop Limit
|
152
|
+
'TRAIL LIT' => :trailing_limit_if_touched, # Trailing Limit if Touched
|
153
|
+
'TRAIL MIT' => :trailing_market_if_touched, # Trailing Market If Touched
|
154
|
+
'PEG MKT' => :pegged_to_market, # Pegged-to-Market
|
155
|
+
'REL' => :relative, # Relative
|
156
|
+
'BOX TOP' => :box_top, # Box Top
|
157
|
+
'PEG MID' => :pegged_to_midpoint, # Pegged-to-Midpoint
|
158
|
+
'VWAP' => :vwap, # VWAP-Guaranteed
|
159
|
+
'OCA' => :one_cancels_all, # One-Cancels-All
|
160
|
+
'VOL' => :volatility, # Volatility
|
161
|
+
'SCALE' => :scale, # Scale
|
162
|
+
'NONE' => :none, # Used to indicate no hedge in :delta_neutral_order_type
|
163
|
+
'None' => :none, # Used to indicate no hedge in :delta_neutral_order_type
|
164
|
+
}.freeze
|
165
|
+
|
166
|
+
# Valid security types (sec_type attribute of IB::Contract)
|
167
|
+
SECURITY_TYPES =
|
168
|
+
{'STK' => :stock,
|
169
|
+
'OPT' => :option,
|
170
|
+
'FUT' => :future,
|
171
|
+
'IND' => :index,
|
172
|
+
'FOP' => :futures_option,
|
173
|
+
'CASH' => :forex,
|
174
|
+
'BOND' => :bond,
|
175
|
+
'WAR' => :warrant,
|
176
|
+
'FUND' => :fund, # ETF?
|
177
|
+
'BAG' => :bag}.freeze
|
178
|
+
|
179
|
+
# Obtain symbolic value from given property code:
|
180
|
+
# VALUES[:side]['B'] -> :buy
|
181
|
+
VALUES = {
|
182
|
+
:sec_type => SECURITY_TYPES,
|
183
|
+
:order_type => ORDER_TYPES,
|
184
|
+
:delta_neutral_order_type => ORDER_TYPES,
|
185
|
+
|
186
|
+
:origin => {0 => :customer, 1 => :firm},
|
187
|
+
:volatility_type => {1 => :daily, 2 => :annual},
|
188
|
+
:reference_price_type => {1 => :average, 2 => :bid_or_ask},
|
189
|
+
|
190
|
+
# This property encodes differently for ComboLeg and Order objects,
|
191
|
+
# we use ComboLeg codes and transcode for Order codes as needed
|
192
|
+
:open_close =>
|
193
|
+
{0 => :same, # Default for Legs, same as the parent (combo) security.
|
194
|
+
1 => :open, # Open. For Legs, this value is only used by institutions.
|
195
|
+
2 => :close, # Close. For Legs, this value is only used by institutions.
|
196
|
+
3 => :unknown}, # WTF
|
197
|
+
|
198
|
+
:right =>
|
199
|
+
{'' => :none, # Not an option
|
200
|
+
'P' => :put,
|
201
|
+
'C' => :call},
|
202
|
+
|
203
|
+
:side => # AKA action
|
204
|
+
{'B' => :buy, # or BOT
|
205
|
+
'S' => :sell, # or SLD
|
206
|
+
'T' => :short, # short
|
207
|
+
'X' => :short_exempt # Short Sale Exempt action. This allows some orders
|
208
|
+
# to be exempt from the SEC recent changes to Regulation SHO, which
|
209
|
+
# eliminated the old uptick rule and replaced it with a new "circuit breaker"
|
210
|
+
# rule, and allows some orders to be exempt from the new rule.
|
211
|
+
},
|
212
|
+
|
213
|
+
:short_sale_slot =>
|
214
|
+
{0 => :default, # The only valid option for retail customers
|
215
|
+
1 => :broker, # Shares are at your clearing broker, institutions
|
216
|
+
2 => :third_party}, # Shares will be delivered from elsewhere, institutions
|
217
|
+
|
218
|
+
:oca_type =>
|
219
|
+
{0 => :none, # Not a member of OCA group
|
220
|
+
1 => :cancel_with_block, # Cancel all remaining orders with block
|
221
|
+
2 => :reduce_with_block, # Remaining orders are reduced in size with block
|
222
|
+
3 => :reduce_no_block}, # Remaining orders are reduced in size with no block
|
223
|
+
|
224
|
+
:auction_strategy =>
|
225
|
+
{0 => :none, # Not a BOX order
|
226
|
+
1 => :match,
|
227
|
+
2 => :improvement,
|
228
|
+
3 => :transparent},
|
229
|
+
|
230
|
+
:trigger_method =>
|
231
|
+
{0 => :default, # "double bid/ask" used for OTC/US options, "last" otherswise.
|
232
|
+
1 => :double_bid_ask, # stops are triggered by 2 consecutive bid or ask prices.
|
233
|
+
2 => :last, # stops are triggered based on the last price.
|
234
|
+
3 => :double_last,
|
235
|
+
4 => :bid_ask, # bid >= trigger price for buy orders, ask <= trigger for sell orders
|
236
|
+
7 => :last_or_bid_ask, # bid OR last price >= trigger price for buy orders
|
237
|
+
8 => :mid_point}, # midpoint >= trigger price for buy orders and the
|
238
|
+
# spread between the bid and ask must be less than 0.1% of the midpoint
|
239
|
+
|
240
|
+
:hedge_type =>
|
241
|
+
{'D' => :delta, # parent order is an option and the child order is a stock
|
242
|
+
'B' => :beta, # offset market risk by entering into a position with
|
243
|
+
# another contract based on the system or user-defined beta
|
244
|
+
'F' => :forex, # offset risk with currency different from your base currency
|
245
|
+
'P' => :pair}, # trade a mis-valued pair of contracts and provide the
|
246
|
+
# ratio between the parent and hedging child order
|
247
|
+
|
248
|
+
:clearing_intent =>
|
249
|
+
{'' => :none,
|
250
|
+
'IB' => :ib,
|
251
|
+
'AWAY' => :away,
|
252
|
+
'PTA' => :post_trade_allocation},
|
253
|
+
|
254
|
+
:delta_neutral_clearing_intent =>
|
255
|
+
{'' => :none,
|
256
|
+
'IB' => :ib,
|
257
|
+
'AWAY' => :away,
|
258
|
+
'PTA' => :post_trade_allocation},
|
259
|
+
|
260
|
+
:tif =>
|
261
|
+
{'DAY' => :day,
|
262
|
+
'GAT' => :good_after_time,
|
263
|
+
'GTD' => :good_till_date,
|
264
|
+
'GTC' => :good_till_cancelled,
|
265
|
+
'IOC' => :immediate_or_cancel},
|
266
|
+
|
267
|
+
:rule_80a =>
|
268
|
+
{'I' => :individual,
|
269
|
+
'A' => :agency,
|
270
|
+
'W' => :agent_other_member,
|
271
|
+
'J' => :individual_ptia,
|
272
|
+
'U' => :agency_ptia,
|
273
|
+
'M' => :agent_other_member_ptia,
|
274
|
+
'K' => :individual_pt,
|
275
|
+
'Y' => :agency_pt,
|
276
|
+
'N' => :agent_other_member_pt},
|
277
|
+
|
278
|
+
:opt? => # TODO: unknown Order property, like OPT_BROKER_DEALER... in Order.java
|
279
|
+
{'?' => :unknown,
|
280
|
+
'b' => :broker_dealer,
|
281
|
+
'c' => :customer,
|
282
|
+
'f' => :firm,
|
283
|
+
'm' => :isemm,
|
284
|
+
'n' => :farmm,
|
285
|
+
'y' => :specialist},
|
286
|
+
|
287
|
+
}.freeze
|
288
|
+
|
289
|
+
# Obtain property code from given symbolic value:
|
290
|
+
# CODES[:side][:buy] -> 'B'
|
291
|
+
CODES = Hash[VALUES.map { |property, hash| [property, hash.invert] }].freeze
|
292
|
+
|
293
|
+
# Most common property processors
|
294
|
+
PROPS = {:side =>
|
295
|
+
{:set => proc { |val| # BUY(BOT)/SELL(SLD)/SSHORT/SSHORTX
|
296
|
+
self[:side] = case val.to_s.upcase
|
297
|
+
when /SHORT.*X|\AX\z/
|
298
|
+
'X'
|
299
|
+
when /SHORT|\AT\z/
|
300
|
+
'T'
|
301
|
+
when /\AB/
|
302
|
+
'B'
|
303
|
+
when /\AS/
|
304
|
+
'S'
|
305
|
+
end },
|
306
|
+
:validate =>
|
307
|
+
{:format =>
|
308
|
+
{:with => /\Abuy\z|\Asell\z|\Ashort\z|\Ashort_exempt\z/,
|
309
|
+
:message => "should be buy/sell/short"}
|
310
|
+
}
|
311
|
+
},
|
312
|
+
|
313
|
+
:open_close =>
|
314
|
+
{:set => proc { |val|
|
315
|
+
self[:open_close] = case val.to_s.upcase[0..0]
|
316
|
+
when 'S', '0' # SAME
|
317
|
+
0
|
318
|
+
when 'O', '1' # OPEN
|
319
|
+
1
|
320
|
+
when 'C', '2' # CLOSE
|
321
|
+
2
|
322
|
+
when 'U', '3' # Unknown
|
323
|
+
3
|
324
|
+
end
|
325
|
+
},
|
326
|
+
:validate =>
|
327
|
+
{:format =>
|
328
|
+
{:with => /\Asame\z|\Aopen\z|\Aclose\z|\Aunknown\z/,
|
329
|
+
:message => "should be same/open/close/unknown"}
|
330
|
+
},
|
331
|
+
}
|
332
|
+
}.freeze
|
333
|
+
|
334
|
+
end # module IB
|
data/lib/ib/db.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# By requiring this file, we make all IB:Models database-backed ActiveRecord subclasses
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
module IB
|
6
|
+
module DB
|
7
|
+
|
8
|
+
def self.logger= logger
|
9
|
+
ActiveRecord::Base.logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
# Use this method to establish DB connection unless you're running on Rails
|
13
|
+
def self.connect config
|
14
|
+
|
15
|
+
# Use ib prefix for all DB tables
|
16
|
+
ActiveRecord::Base.table_name_prefix = "ib_"
|
17
|
+
|
18
|
+
# Get rid of nasty conversion issues
|
19
|
+
ActiveRecord::Base.default_timezone = :utc
|
20
|
+
Time.zone = 'UTC'
|
21
|
+
|
22
|
+
ActiveRecord::Base.establish_connection(config)
|
23
|
+
#ActiveRecord.colorize_logging = false
|
24
|
+
end
|
25
|
+
|
26
|
+
end # module DB
|
27
|
+
end
|
28
|
+
|
29
|
+
|
data/lib/ib/engine.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module IB
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
isolate_namespace Ib
|
4
|
+
|
5
|
+
#paths["app"] # => ["app"]
|
6
|
+
#paths["app/controllers"] # => ["app/controllers"]
|
7
|
+
#paths["app/helpers"] # => ["app/helpers"]
|
8
|
+
paths["app/models"] = "lib/models"
|
9
|
+
#paths["app/views"] # => ["app/views"]
|
10
|
+
#paths["lib"] # => ["lib"]
|
11
|
+
#paths["lib/tasks"] # => ["lib/tasks"]
|
12
|
+
#paths["config"] # => ["config"]
|
13
|
+
#paths["config/initializers"] # => ["config/initializers"]
|
14
|
+
#paths["config/locales"] # => ["config/locales"]
|
15
|
+
#paths["config/routes"] # => ["config/routes.rb"]
|
16
|
+
|
17
|
+
config.generators do |gen|
|
18
|
+
gen.integration_tool :rspec
|
19
|
+
gen.test_framework :rspec
|
20
|
+
gen.helper_specs false
|
21
|
+
# gen.view_specs false
|
22
|
+
end
|
23
|
+
|
24
|
+
config.to_prepare do
|
25
|
+
end
|
26
|
+
|
27
|
+
initializer "ib.active_record" do |app|
|
28
|
+
ActiveSupport.on_load :active_record do
|
29
|
+
require 'ib/db'
|
30
|
+
require 'ib/requires'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
data/lib/ib/errors.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module IB
|
2
|
+
|
3
|
+
# Error handling
|
4
|
+
class Error < RuntimeError
|
5
|
+
end
|
6
|
+
|
7
|
+
class ArgumentError < ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
class SymbolError < ArgumentError
|
11
|
+
end
|
12
|
+
|
13
|
+
class LoadError < LoadError
|
14
|
+
end
|
15
|
+
|
16
|
+
class FlexError < RuntimeError
|
17
|
+
end
|
18
|
+
|
19
|
+
end # module IB
|
20
|
+
|
21
|
+
# Patching Object with universally accessible top level error method.
|
22
|
+
# The method is used throughout the lib instead of plainly raising exceptions.
|
23
|
+
# This allows lib user to easily inject user-specific error handling into the lib
|
24
|
+
# by just replacing Object#error method.
|
25
|
+
def error message, type=:standard, backtrace=nil
|
26
|
+
e = case type
|
27
|
+
when :standard
|
28
|
+
IB::Error.new message
|
29
|
+
when :args
|
30
|
+
IB::ArgumentError.new message
|
31
|
+
when :symbol
|
32
|
+
IB::SymbolError.new message
|
33
|
+
when :load
|
34
|
+
IB::LoadError.new message
|
35
|
+
when :flex
|
36
|
+
IB::FlexError.new message
|
37
|
+
end
|
38
|
+
e.set_backtrace(backtrace) if backtrace
|
39
|
+
raise e
|
40
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class Time
|
2
|
+
# Render datetime in IB format (zero padded "yyyymmdd HH:mm:ss")
|
3
|
+
def to_ib
|
4
|
+
"#{year}#{sprintf("%02d", month)}#{sprintf("%02d", day)} " +
|
5
|
+
"#{sprintf("%02d", hour)}:#{sprintf("%02d", min)}:#{sprintf("%02d", sec)}"
|
6
|
+
end
|
7
|
+
end # Time
|
8
|
+
|
9
|
+
class Numeric
|
10
|
+
# Conversion 0/1 into true/false
|
11
|
+
def to_bool
|
12
|
+
self == 0 ? false : true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class TrueClass
|
17
|
+
def to_bool
|
18
|
+
self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class FalseClass
|
23
|
+
def to_bool
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class String
|
29
|
+
def to_bool
|
30
|
+
case self.chomp.upcase
|
31
|
+
when 'TRUE', 'T', '1'
|
32
|
+
true
|
33
|
+
when 'FALSE', 'F', '0', ''
|
34
|
+
false
|
35
|
+
else
|
36
|
+
error "Unable to convert #{self} to bool"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class NilClass
|
42
|
+
# We still need to pass on nil, meaning: no value
|
43
|
+
def to_bool
|
44
|
+
self
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Symbol
|
49
|
+
def to_f
|
50
|
+
0
|
51
|
+
end
|
52
|
+
|
53
|
+
# ActiveModel serialization depends on this method
|
54
|
+
def <=> other
|
55
|
+
to_s <=> other.to_s
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Object
|
60
|
+
# We still need to pass on nil, meaning: no value
|
61
|
+
def to_sup
|
62
|
+
self.to_s.upcase unless self.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
### Patching Object#error in ib/errors
|
67
|
+
# def error message, type=:standard
|
68
|
+
|
69
|
+
### Patching Object#log, #default_logger= in ib/logger
|
70
|
+
# def default_logger
|
71
|
+
# def default_logger= logger
|
72
|
+
# def log *args
|