lib/ib/option-chain.rb in ib-extensions-1.1 vs lib/ib/option-chain.rb in ib-extensions-1.2

- old
+ new

@@ -7,21 +7,24 @@ class Contract - # returns the Option Chain of the contract (if available) + # returns the Option Chain (monthly options, expiry: third friday) + # of the contract (if available) # + # ## parameters - ### right:: :call, :put, :straddle - ### ref_price:: :request or a numeric value + ### right:: :call, :put, :straddle ( default: :put ) + ### ref_price:: :request or a numeric value ( default: :request ) ### sort:: :strike, :expiry ### exchange:: List of Exchanges to be queried (Blank for all available Exchanges) - def option_chain ref_price: :request, right: :put, sort: :strike, exchange: '' + ### trading_class ( optional ) + def option_chain ref_price: :request, right: :put, sort: :strike, exchange: '', trading_class: nil ib = Connection.current - finalize = Queue.new + finalize = Queue.new ## Enable Cashing of Definition-Matrix @option_chain_definition ||= [] my_req = nil @@ -58,31 +61,31 @@ sec_type: c[:sec_type] finalize.pop # wait until data appeared #i=0; loop { sleep 0.1; break if i> 1000 || finalize; i+=1 } - ib.unsubscribe sub_sdop , sub_ocd + ib.unsubscribe sub_sdop, sub_ocd else Connection.logger.info { "#{to_human} : using cached data" } end # ----------------------------------------------------------------------------------------------------- # select values and assign to options # unless @option_chain_definition.blank? - requested_strikes = if block_given? + requested_strikes = if block_given? ref_price = market_price if ref_price == :request if ref_price.nil? - ref_price = @option_chain_definition[:strikes].min + - ( @option_chain_definition[:strikes].max - - @option_chain_definition[:strikes].min ) / 2 + ref_price = @option_chain_definition[:strikes].min + + ( @option_chain_definition[:strikes].max - + @option_chain_definition[:strikes].min ) / 2 Connection.logger.warn { "#{to_human} :: market price not set – using midpoint of available strikes instead: #{ref_price.to_f}" } end atm_strike = @option_chain_definition[:strikes].min_by { |x| (x - ref_price).abs } the_grouped_strikes = @option_chain_definition[:strikes].group_by{|e| e <=> atm_strike} begin - the_strikes = yield the_grouped_strikes + the_strikes = yield the_grouped_strikes the_strikes.unshift atm_strike unless the_strikes.first == atm_strike # the first item is the atm-strike the_strikes rescue Connection.logger.error "#{to_human} :: not enough strikes :#{@option_chain_definition[:strikes].map(&:to_f).join(',')} " [] @@ -90,38 +93,38 @@ else @option_chain_definition[:strikes] end # third Friday of a month - monthly_expirations = @option_chain_definition[:expirations].find_all{|y| (15..21).include? y.day } + monthly_expirations = @option_chain_definition[:expirations].find_all {|y| (15..21).include? y.day } # puts @option_chain_definition.inspect - option_prototype = -> ( ltd, strike ) do - IB::Option.new symbol: symbol, - exchange: @option_chain_definition[:exchange], - trading_class: @option_chain_definition[:trading_class], - multiplier: @option_chain_definition[:multiplier], - currency: currency, - last_trading_day: ltd, - strike: strike, - right: right + option_prototype = -> ( ltd, strike ) do + IB::Option.new( symbol: symbol, + exchange: @option_chain_definition[:exchange], + trading_class: @option_chain_definition[:trading_class], + multiplier: @option_chain_definition[:multiplier], + currency: currency, + last_trading_day: ltd, + strike: strike, + right: right).verify &.first end options_by_expiry = -> ( schema ) do # Array: [ yymm -> Options] prepares for the correct conversion to a Hash Hash[ monthly_expirations.map do | l_t_d | - [ l_t_d.strftime('%y%m').to_i , schema.map{ | strike | option_prototype[ l_t_d, strike ]}.compact ] + [ l_t_d.strftime('%y%m').to_i , schema.map { | strike | option_prototype[ l_t_d, strike ]}.compact ] end ] # by Hash[ ] end options_by_strike = -> ( schema ) do Hash[ schema.map do | strike | - [ strike , monthly_expirations.map{ | l_t_d | option_prototype[ l_t_d, strike ]}.compact ] + [ strike , monthly_expirations.map { | l_t_d | option_prototype[ l_t_d, strike ]}.compact ] end ] # by Hash[ ] end if sort == :strike - options_by_strike[ requested_strikes ] + options_by_strike[ requested_strikes ] else - options_by_expiry[ requested_strikes ] + options_by_expiry[ requested_strikes ] end else Connection.logger.error "#{to_human} ::No Options available" nil # return_value end @@ -135,60 +138,32 @@ end # return InTheMoneyOptions - def itm_options count: 5, right: :put, ref_price: :request, sort: :strike - option_chain( right: right, ref_price: ref_price, sort: sort ) do | chain | + def itm_options count: 5, right: :put, ref_price: :request, sort: :strike, exchange: '' + option_chain( right: right, ref_price: ref_price, sort: sort, exchange: exchange ) do | chain | if right == :put above_market_price_strikes = chain[1][0..count-1] else below_market_price_strikes = chain[-1][-count..-1].reverse end # branch end end # def # return OutOfTheMoneyOptions - def otm_options count: 5, right: :put, ref_price: :request, sort: :strike - option_chain( right: right, ref_price: ref_price, sort: sort ) do | chain | + def otm_options count: 5, right: :put, ref_price: :request, sort: :strike, exchange: '' + option_chain( right: right, ref_price: ref_price, sort: sort, exchange: exchange ) do | chain | if right == :put # puts "Chain: #{chain}" below_market_price_strikes = chain[-1][-count..-1].reverse else above_market_price_strikes = chain[1][0..count-1] end end end - def associate_ticdata - - tws= IB::Connection.current # get the initialized ib-ruby instance - the_id = nil - finalize= false - # switch to delayed data - tws.send_message :RequestMarketDataType, :market_data_type => :delayed - - s_id = tws.subscribe(:TickSnapshotEnd) { |msg| finalize = true if msg.ticker_id == the_id } - - sub_id = tws.subscribe(:TickPrice, :TickSize, :TickGeneric, :TickOption) do |msg| - self.bars << msg.the_data if msg.ticker_id == the_id - end - - # initialize »the_id« that is used to identify the received tick messages - # by firing the market data request - the_id = tws.send_message :RequestMarketData, contract: self , snapshot: true - - #keep the method-call running until the request finished - #and cancel subscriptions to the message handler. - Thread.new do - i=0; loop{ i+=1; sleep 0.1; break if finalize || i > 1000 } - tws.unsubscribe sub_id - tws.unsubscribe s_id - #puts "#{symbol} data gathered" - end # method returns the (running) thread - - end # def end # class