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,14 @@
1
+ module IB
2
+ class Index < Contract
3
+ validates_format_of :sec_type, :with => /\Aind\z/,
4
+ :message => "should be a Index"
5
+ def default_attributes
6
+ super.merge :sec_type => 'IND'
7
+ end
8
+ def to_human
9
+ "<Index: " + [symbol, currency].join(" ") + " (#{description}) >"
10
+ end
11
+
12
+ end
13
+ end
14
+
@@ -0,0 +1,149 @@
1
+ module IB
2
+ class Option < Contract
3
+
4
+ validates_numericality_of :strike, :greater_than => 0
5
+ validates_format_of :sec_type, :with => /\Aoption\z/,
6
+ :message => "should be an option"
7
+ validates_format_of :local_symbol, :with => /\A\w+\s*\d{6}[pcPC]\d{8}$|\A\z/,
8
+ :message => "invalid OSI code"
9
+ validates_format_of :right, :with => /\Aput$|^call\z/,
10
+ :message => "should be put or call"
11
+
12
+
13
+ # introduce Option.greek with reference to IB::OptionDetail-dataset
14
+ #
15
+ has_one :greek , as: :option_detail
16
+ # For Options, this is contract's OSI (Option Symbology Initiative) name/code
17
+ alias osi local_symbol
18
+
19
+ def osi= value
20
+ # Normalize to 21 char
21
+ self.local_symbol = value.sub(/ /, ' '*(22-value.size))
22
+ end
23
+
24
+ # Make valid IB Contract definition from OSI (Option Symbology Initiative) code.
25
+ # NB: Simply making a new Contract with *local_symbol* (osi) property set to a
26
+ # valid OSI code works just as well, just do NOT set *expiry*, *right* or
27
+ # *strike* properties in this case.
28
+ # This class method provided as a backup and shows how to analyse OSI codes.
29
+ def self.from_osi osi
30
+
31
+ # Parse contract's OSI (OCC Option Symbology Initiative) code
32
+ args = osi.match(/(\w+)\s?(\d\d)(\d\d)(\d\d)([pcPC])(\d+)/).to_a.drop(1)
33
+ symbol = args.shift
34
+ year = 2000 + args.shift.to_i
35
+ month = args.shift.to_i
36
+ day = args.shift.to_i
37
+ right = args.shift.upcase
38
+ strike = args.shift.to_i/1000.0
39
+
40
+ # Set correct expiry date - IB expiry date differs from OSI if expiry date
41
+ # falls on Saturday (see https://github.com/arvicco/option_mower/issues/4)
42
+ expiry_date = Time.utc(year, month, day)
43
+ expiry_date = Time.utc(year, month, day-1) if expiry_date.wday == 6
44
+
45
+ new :symbol => symbol,
46
+ :exchange => "SMART",
47
+ :expiry => expiry_date.to_ib[2..7], # YYMMDD
48
+ :right => right,
49
+ :strike => strike
50
+ end
51
+
52
+ def default_attributes
53
+ super.merge :sec_type => :option
54
+ #self[:description] ||= osi ? osi : "#{symbol} #{strike} #{right} #{expiry}"
55
+ end
56
+ def == other
57
+ super(other) || ( # finish positive, if contract#== is true
58
+ # otherwise, we most probably compare the response from IB with our selfmade input
59
+ exchange == other.exchange &&
60
+ include_expired == other.include_expired &&
61
+ sec_type == other.sec_type &&
62
+ multiplier == other.multiplier &&
63
+ strike == other.strike &&
64
+ right == other.right &&
65
+ multiplier == other.multiplier &&
66
+ expiry == other.expiry )
67
+
68
+ end
69
+
70
+
71
+ # returns the verified option for the next (regular) expiry of the contract.
72
+ #
73
+ # Argument: Reference date, provided as Date-Object or as parseable string or integer, i.e
74
+ # Symbols::Options.rut.merge( strike: 2000 ).next_expiry( "2405")
75
+ # returns "<Option: RUT 20240516 put 2000.0 SMART USD>" instead of
76
+ # "<Option: RUT 20240517 put 2000.0 SMART USD>" because the third friday is a bank holiday
77
+ #
78
+ # Optionally a block can be provided, returning the expiry to check in the format "yyyymmdd"
79
+ #
80
+ # if verify is not available, the option is just returned.
81
+ #
82
+ # (always returns a new option, respects immutability of the IB::Contract)
83
+ #
84
+ # raises IB::LoadError if no Option is available for the expiry given.
85
+ #
86
+ def next_expiry d = Date.today
87
+ # get the next regular option
88
+ exp = block_given? ? yield : self.class.next_expiry( d )
89
+ # check if the option exists, otherwise fetch the previous date until a valid contract is detected
90
+ if IB::Connection.current.plugins.include? 'verify'
91
+ real_option = nil
92
+ loop do
93
+ real_option = merge( expiry: exp ).verify.first
94
+ break unless real_option.nil?
95
+ exp = ( exp.to_i - 1 ).to_s
96
+ error( "No suitable next expiry option found", :load ) if exp[-2..-1] == "00"
97
+ end
98
+ real_option
99
+ else
100
+ merge( expiry: exp, last_trading_day: Date.parse( exp ).strftime( "%Y-%m-%d" ) )
101
+ end
102
+
103
+ end
104
+
105
+ # returns the third friday of the (next) month (class method)
106
+ #
107
+ # Argument: can either be Date, a String which parses to a Date or
108
+ # an Integer, yymm yyyymm or yyyymmdd --> 2406 or 202406 or 20240618
109
+ #
110
+ # if called with a digit, this is interpretated a day of the current month
111
+ #
112
+ def self.next_expiry base = Date.today
113
+
114
+ c = 0
115
+ begin
116
+ base_date = if base.is_a? Date
117
+ [ base.year, base.month ]
118
+ else
119
+ (base = Date.parse(base.to_s)).then { | d | [ d.year,d.month ] }
120
+ end.then{ |y,m| Date.new y,m }
121
+ rescue Date::Error => e
122
+ base = base.to_s + "01"
123
+ c = c + 1
124
+ retry if c == 1
125
+ end
126
+ error "Next-Expiry: Not a valid date: #{base}" if base_date.nil?
127
+ friday = 5
128
+ base_wday = base_date.wday
129
+ b= base_date + ( friday > base_wday ? friday - base_wday : 7 - base_wday + friday ) + 14
130
+
131
+ if b < base
132
+ next_expiry base.then{| y | a = y + 25; a.strftime "%Y%m01" }
133
+ else
134
+ b.strftime "%Y%m%d"
135
+ end
136
+ end
137
+
138
+ def to_human
139
+ "<Option: " + [symbol, expiry, right, strike, exchange, currency].join(" ") + ">"
140
+ end
141
+
142
+ end # class Option
143
+
144
+ class FutureOption < Option
145
+ def default_attributes
146
+ super.merge :sec_type => :futures_option
147
+ end
148
+ end
149
+ end # module IB
@@ -0,0 +1,84 @@
1
+ module IB
2
+ # Additional Option properties and Option-Calculations
3
+ class OptionDetail < Base
4
+ include BaseProperties
5
+
6
+ prop :delta, :gamma, :vega, :theta, # greeks
7
+ :implied_volatility,
8
+ :pv_dividend, # anticipated Dividend
9
+ :under_price, # price of the Underlying
10
+ :option_price,
11
+ :close_price,
12
+ :open_tick,
13
+ :bid_price,
14
+ :ask_price,
15
+ :prev_strike,
16
+ :next_strike,
17
+ :prev_expiry,
18
+ :next_expiry,
19
+ :option_price,
20
+ :updated_at
21
+ belongs_to :option
22
+
23
+ # returns true if all datafields are filled with reasonal data
24
+ def complete?
25
+ fields= [ :delta, :gamma, :vega, :theta,
26
+ :implied_volatility, :pv_dividend, :open_tick,
27
+ :under_price, :option_price, :close_price, :bid_price, :ask_price]
28
+
29
+ !fields.detect{|y| self.send(y).nil?}
30
+
31
+ end
32
+
33
+ # true if greeks are present
34
+ def greeks? # theta and implied volatility are not always present
35
+ fields= [ :delta, :gamma, :vega ]
36
+
37
+ !fields.detect{|y| self.send(y).nil?}
38
+
39
+ end
40
+
41
+ # true if prices are received
42
+ def prices?
43
+ fields = [:implied_volatility, :under_price, :option_price]
44
+ !fields.detect{|y| self.send(y).nil?}
45
+ end
46
+
47
+ def iv
48
+ implied_volatility
49
+ end
50
+
51
+ def spread
52
+ bid_price - ask_price
53
+ end
54
+
55
+ def to_human
56
+ outstr= ->( item ) { if item.nil? then "--" else sprintf("%g" , item) end }
57
+ att = " optionPrice: #{ outstr[ option_price ]}, UnderlyingPrice: #{ outstr[ under_price] } impl.Vola: #{ outstr[ implied_volatility ]} ; dividend: #{ outstr[ pv_dividend ]}; "
58
+ greeks = "Greeks:: delta: #{ outstr[ delta ] }; gamma: #{ outstr[ gamma ]}, vega: #{ outstr[ vega ] }; theta: #{ outstr[ theta ]}"
59
+ prices= " close: #{ outstr[ close_price ]}; bid: #{ outstr[ bid_price ]}; ask: #{ outstr[ ask_price ]} "
60
+ if complete?
61
+ "< "+ prices + "\n" + att + "\n" + greeks + " >"
62
+ elsif prices?
63
+ "< " + att + greeks + " >"
64
+ else
65
+ "< " + greeks + " >"
66
+ end
67
+
68
+ end
69
+
70
+ def table_header
71
+ [ 'Greeks', 'price', 'impl. vola', 'dividend', 'delta','gamma', 'vega' , 'theta']
72
+ end
73
+
74
+ def table_row
75
+ outstr= ->( item ) { { value: item.nil? ? "--" : sprintf("%g" , item) , alignment: :right } }
76
+ outprice= ->( item ) { { value: item.nil? ? "--" : sprintf("%7.2f" , item) , alignment: :right } }
77
+ option_short = ->{"#{option.right} #{option.symbol}#{ "/"+ option.trading_class unless option.trading_class == option.symbol } #{option.expiry} #{option.strike}"}
78
+ [ option_short[], outprice[ option_price ], outprice[ implied_volatility ],
79
+ outprice[ pv_dividend ],
80
+ outprice[ delta ], outprice[ gamma ], outprice[ vega ] , outprice[ theta ] ]
81
+ end
82
+
83
+ end # class
84
+ end # module