Class: IB::Contract
- Inherits:
-
Object
- Object
- IB::Contract
- Defined in:
- lib/ib/verify.rb,
lib/ib/eod.rb,
lib/ib/market-price.rb,
lib/ib/option-chain.rb
Overview
end
Instance Method Summary collapse
- #associate_ticdata ⇒ Object
-
#atm_options(ref_price: :request, right: :put) ⇒ Object
return a set of AtTheMoneyOptions.
-
#eod(start: nil, to: Date.today, duration: nil, what: :trades) ⇒ Object
puts Symbols::Stocks.wfc.eod( to: Date.new(2019,10,9), duration: 3 ) <Bar: 2019-10-04 wap 48.964 OHLC 48.61 49.25 48.54 49.21 trades 9899 vol 50561> <Bar: 2019-10-07 wap 48.9445 OHLC 48.91 49.29 48.75 48.81 trades 10317 vol 50189> <Bar: 2019-10-08 wap 47.9165 OHLC 48.25 48.34 47.55 47.82 trades 12607 vol 53577>.
-
#itm_options(count: 5, right: :put, ref_price: :request, sort: :strike) ⇒ Object
return InTheMoneyOptions.
-
#market_price(delayed: true, thread: false) ⇒ Object
if that fails use alternative exchanges (look to Contract.valid_exchanges).
-
#nessesary_attributes ⇒ Object
returns a hash.
-
#option_chain(ref_price: :request, right: :put, sort: :strike, exchange: '') ⇒ Object
returns the Option Chain of the contract (if available).
-
#otm_options(count: 5, right: :put, ref_price: :request, sort: :strike) ⇒ Object
return OutOfTheMoneyOptions.
-
#verify(thread: nil, &b) ⇒ Object
verifies the contract.
-
#verify! ⇒ Object
depreciated: Do not use anymore.
Instance Method Details
#associate_ticdata ⇒ Object
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 |
# File 'lib/ib/option-chain.rb', line 163 def associate_ticdata tws= IB::Connection.current # get the initialized ib-ruby instance the_id = nil finalize= false # switch to delayed data tws. :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. << 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. :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 |
#atm_options(ref_price: :request, right: :put) ⇒ Object
return a set of AtTheMoneyOptions
131 132 133 134 135 136 137 |
# File 'lib/ib/option-chain.rb', line 131 def ref_price: :request, right: :put option_chain( right: right, ref_price: ref_price, sort: :expiry) do | chain | chain[0] end end |
#eod(start: nil, to: Date.today, duration: nil, what: :trades) ⇒ Object
puts Symbols::Stocks.wfc.eod( to: Date.new(2019,10,9), duration: 3 ) <Bar: 2019-10-04 wap 48.964 OHLC 48.61 49.25 48.54 49.21 trades 9899 vol 50561> <Bar: 2019-10-07 wap 48.9445 OHLC 48.91 49.29 48.75 48.81 trades 10317 vol 50189> <Bar: 2019-10-08 wap 47.9165 OHLC 48.25 48.34 47.55 47.82 trades 12607 vol 53577>
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/ib/eod.rb', line 93 def eod start:nil, to: Date.today, duration: nil , what: :trades tws = IB::Connection.current recieved = Queue.new r = nil # the hole response is transmitted at once! a = tws.subscribe(IB::Messages::Incoming::HistoricalData) do |msg| if msg.request_id == con_id # msg.results.each { |entry| puts " #{entry}" } r = block_given? ? msg.results.map{|y| yield y} : msg.results end recieved.push Time.now end b = tws.subscribe( IB::Messages::Incoming::Alert) do |msg| if [321,162,200].include? msg.code tws.logger.info msg. # TWS Error 200: No security definition has been found for the request # TWS Error 354: Requested market data is not subscribed. # TWS Error 162 # Historical Market Data Service error recieved.close end end duration = if duration.present? duration.is_a?(String) ? duration : duration.to_s + " D" elsif start.present? BuisinesDays.business_days_between(start, to).to_s + " D" else "1 D" end tws. IB::Messages::Outgoing::RequestHistoricalData.new( :request_id => con_id, :contract => self, :end_date_time => to.to_time.to_ib, # Time.now.to_ib, :duration => duration, # ? :bar_size => :day1, # IB::BAR_SIZES.key(:hour)? :what_to_show => what, :use_rth => 0, :format_date => 2, :keep_up_todate => 0) Timeout::timeout(5) do # max 5 sec. sleep 0.1 recieved.pop # blocks until a message is ready on the queue break if recieved.closed? || recieved.empty? # finish if data received end tws.unsubscribe a tws.unsubscribe b r # the collected result end |
#itm_options(count: 5, right: :put, ref_price: :request, sort: :strike) ⇒ Object
return InTheMoneyOptions
140 141 142 143 144 145 146 147 148 |
# File 'lib/ib/option-chain.rb', line 140 def count: 5, right: :put, ref_price: :request, sort: :strike option_chain( right: right, ref_price: ref_price, sort: sort ) 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 |
#market_price(delayed: true, thread: false) ⇒ Object
if that fails use alternative exchanges (look to Contract.valid_exchanges)
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/ib/market-price.rb', line 52 def market_price delayed: true, thread: false tws= Connection.current # get the initialized ib-ruby instance the_id , the_price = nil, nil tickdata = Hash.new # define requested tick-attributes last, close, bid, ask = [ [ :delayed_last , :last_price ] , [:delayed_close , :close_price ], [ :delayed_bid , :bid_price ], [ :delayed_ask , :ask_price ]] request_data_type = delayed ? :frozen_delayed : :frozen tws. :RequestMarketDataType, :market_data_type => IB::MARKET_DATA_TYPES.rassoc( request_data_type).first #keep the method-call running until the request finished #and cancel subscriptions to the message handler # method returns the (running) thread th = Thread.new do finalize, raise_delay_alert = false, false s_id = tws.subscribe(:TickSnapshotEnd){|x| finalize = true if x.ticker_id == the_id } e_id = tws.subscribe(:Alert){|x| raise_delay_alert = true if x.code == 354 && x.error_id == the_id } # TWS Error 354: Requested market data is not subscribed. # r_id = tws.subscribe(:TickRequestParameters) {|x| } # raise_snapshot_alert = true if x.snapshot_permissions.to_i.zero? && x.ticker_id == the_id } # subscribe to TickPrices sub_id = tws.subscribe(:TickPrice ) do |msg| #, :TickSize, :TickGeneric, :TickOption) do |msg| [last,close,bid,ask].each do |x| tickdata[x] = msg.the_data[:price] if x.include?( IB::TICK_TYPES[ msg.the_data[:tick_type]]) # fast exit condition finalize = true if tickdata.size >= 4 || ( tickdata[bid].present? && tickdata[ask].present? ) end 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. :RequestMarketData, contract: self , snapshot: true # todo implement config-feature to set timeout in configuration (DRY-Feature) # Alternative zu Timeout # Thread.new do # i=0; loop{ i+=1; sleep 0.1; break if finalize || i > 1000 } i=0; loop{ i+=1; break if i > 1000 || finalize || raise_delay_alert; sleep 0.05 } tws.unsubscribe sub_id, s_id, e_id # reduce :close_price delayed_close to close a.s.o if raise_delay_alert && !delayed error "No Marketdata Subscription, use delayed data <-- #{to_human}" # elsif raise_snapshot_alert # error "No Snapshot Permissions, try alternative exchange <-- #{to_human}" elsif i <= 1000 tz = -> (z){ z.map{|y| y.to_s.split('_')}.flatten.count_duplicates.max_by{|k,v| v}.first.to_sym} data = tickdata.map{|x,y| [tz[x],y]}.to_h valid_data = ->(d){ !(d.to_i.zero? || d.to_i == -1) } self. << data # store raw data in bars the_price = if block_given? yield data # yields {:bid=>0.10142e3, :ask=>0.10144e3, :last=>0.10142e3, :close=>0.10172e3} else # behavior if no block is provided if valid_data[data[:last]] data[:last] elsif valid_data[data[:bid]] (data[:bid]+data[:ask])/2 elsif data[:close].present? data[:close] else nil end end self.misc = the_price if thread # store internally if in thread modus else # i > 1000 tws.logger.info{ "#{to_human} --> No Marketdata received " } end end if thread th # return thread else th.join the_price # return end end |
#nessesary_attributes ⇒ Object
returns a hash
57 58 59 60 61 62 63 64 65 66 |
# File 'lib/ib/verify.rb', line 57 def nessesary_attributes v= { stock: { currency: 'USD', exchange: 'SMART', symbol: nil}, option: { currency: 'USD', exchange: 'SMART', right: 'P', expiry: nil, strike: nil, symbol: nil}, future: { currency: 'USD', exchange: nil, expiry: nil, symbol: nil }, forex: { currency: 'USD', exchange: 'IDEALPRO', symbol: nil } } sec_type.present? ? v[sec_type] : { con_id: nil, exchange: 'SMART' } # enables to use only con_id for verifying # if the contract allows SMART routing end |
#option_chain(ref_price: :request, right: :put, sort: :strike, exchange: '') ⇒ Object
returns the Option Chain of the contract (if available)
parameters
- right
-
:call, :put, :straddle
- ref_price
-
:request or a numeric value
- sort
-
:strike, :expiry
- exchange
-
List of Exchanges to be queried (Blank for all available Exchanges)
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/ib/option-chain.rb', line 19 def option_chain ref_price: :request, right: :put, sort: :strike, exchange: '' ib = Connection.current finalize = Queue.new ## Enable Cashing of Definition-Matrix @option_chain_definition ||= [] my_req = nil # ----------------------------------------------------------------------------------------------------- # get OptionChainDefinition from IB ( instantiate cashed Hash ) if @option_chain_definition.blank? sub_sdop = ib.subscribe( :SecurityDefinitionOptionParameterEnd ) { |msg| finalize.push(true) if msg.request_id == my_req } sub_ocd = ib.subscribe( :OptionChainDefinition ) do | msg | if msg.request_id == my_req = msg.data # transfer the first record to @option_chain_definition if @option_chain_definition.blank? @option_chain_definition = msg.data end # override @option_chain_definition if a decent combination of attributes is met # us- options: use the smart dataset # other options: prefer options of the default trading class if [:exchange] == 'SMART' @option_chain_definition = msg.data finalize.push(true) end if [:trading_class] == symbol @option_chain_definition = msg.data finalize.push(true) end end end c = verify.first # ensure a complete set of attributes my_req = ib. :RequestOptionChainDefinition, con_id: c.con_id, symbol: c.symbol, exchange: c.sec_type == :future ? c.exchange : "", # BOX,CBOE', 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 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? 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 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.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(',')} " [] end 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 } # 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 end = -> ( 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 ] end ] # by Hash[ ] end = -> ( schema ) do Hash[ schema.map do | strike | [ strike , monthly_expirations.map{ | l_t_d | option_prototype[ l_t_d, strike ]}.compact ] end ] # by Hash[ ] end if sort == :strike [ requested_strikes ] else [ requested_strikes ] end else Connection.logger.error "#{to_human} ::No Options available" nil # return_value end end |
#otm_options(count: 5, right: :put, ref_price: :request, sort: :strike) ⇒ Object
return OutOfTheMoneyOptions
151 152 153 154 155 156 157 158 159 160 |
# File 'lib/ib/option-chain.rb', line 151 def count: 5, right: :put, ref_price: :request, sort: :strike option_chain( right: right, ref_price: ref_price, sort: sort ) 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 |
#verify(thread: nil, &b) ⇒ Object
verifies the contract
returns the number of contracts returned by the TWS.
The method accepts a block. The queried contract-Object is accessible there. If multiple contracts are specified, the block is executed with each of these contracts.
Verify returns an Array of contracts. The operation leaves the contract untouched.
Returns nil if the contract could not be verified.
> s = Stock.new symbol: 'AA'
=> #<IB::Stock:0x0000000002626cc0
@attributes={:symbol=>"AA", :con_id=>0, :right=>"", :include_expired=>false,
:sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
> sp = s.verify.first.essential
=> #<IB::Stock:0x00000000025a3cf8
@attributes={:symbol=>"AA", :con_id=>251962528, :exchange=>"SMART", :currency=>"USD",
:strike=>0.0, :local_symbol=>"AA", :multiplier=>0, :primary_exchange=>"NYSE",
:trading_class=>"AA", :sec_type=>"STK", :right=>"", :include_expired=>false}
> s = Stock.new symbol: 'invalid'
=> @attributes={:symbol=>"invalid", :sec_type=>"STK", :currency=>"USD", :exchange=>"SMART"}
> sp = s.verify
=> []
Takes a Block to modify the queried contracts
f = Future.new symbol: ‘M2K’
con_ids = f.verify{ |c| c.con_id }
[412889018, 428519982, 446091466, 461318872, 477836981]
Parameter: thread: (true/false)
If multiple contracts are to be verified, they can be queried simultaneously.
IB::Symbols::W500.map{|c| c.verify(thread: true){ |vc| do_something }}.join
51 52 53 54 |
# File 'lib/ib/verify.rb', line 51 def verify thread: nil, &b return [self] if contract_detail.present? || sec_type == :bag _verify update: false, thread: thread, &b # returns the allocated threads end |
#verify! ⇒ Object
depreciated: Do not use anymore
70 71 72 73 74 75 76 |
# File 'lib/ib/verify.rb', line 70 def verify! c = 0 IB::Connection.logger.warn "Contract.verify! is depreciated. Use \"contract = contract.verify.first\" instead" _verify( update: true){| response | c+=1 } # wait for the returned thread to finish IB::Connection.logger.error { "Multible Contracts detected during verify!." } if c > 1 self end |