To use the market_price feature, include the ib-extensions Gem in the Gemfile and use
 
require 'ib-api' 
require 'ib/market-price' 
in your scripts.

Market-Price

ib-extensions provides a handy IB::Contract#market_price method, easing the process of collecting market price data from the TWS.
Basically IB::Contract.market_price combines the process of sending a :RequestMarketData-Message, collecting the TickType-Response and returning evaluated data. The results can be further customized in a block.

 zn =  Symbols::Futures.zn
 zn.market_price       => 132.78125 
 zn.bars               => [{:bid=>132.765625, :ask=>132.78125, :last=>132.78125, :close=>132.859375}] 
 zn.misc               => {:realtime=>132.78125}

 zn.market_price{|y| y[:close]}    
 => 132.859375

The default response is to return the :last-price, if present. Otherwise the average of :bid and :ask. If this fails too, the :close-price is returned.

Snapshot, delayed and frozen Data

Market data subscriptions are expensive and in many cases not needed. For most contracts, the TWS-API offers delayed data, too. They can be accessed without subscription.

If no marketdata subscription is detected, market_price automatically switches to delayed data.

This behavior can be controlled by the parameter delayed: false

# assuming market data for stocks trading in singapore are not subscribed

 c =  Stock.new symbol: :'C09', exchange: 'SGX', currency: :sgd
 c.market_price delayed: false
  INFO::Requested market data is not subscribed. Delayed market data is not enabled.
  ERROR::<Stock: C09 sgd SGX> --> No marketdata permissions
   => nil 
 
 c.market_price delayed: true
  INFO::Requested market data is not subscribed. Delayed market data is not enabled.
  INFO::<Stock: C09 sgd SGX> --> requesting delayed data
   => 7.67 
 c.bars                => [{:bid=>7.67, :ask=>7.69, :last=>7.67, :close=>7.67}]
 c.misc                => {:delayed=>7.67}

Exercise

Assuming, a watchlist W20 containing 19 single stocks exists.

How to fetch effectively market prices of each of the contracts?
How to extend this to larger collections?

Creating the Watchlist

> symbols = %W( ANW  AEB  AED  AEG  AEH AER  HIVE AJRD AET  AMG  AFL  MITT  AGCO  A  AEM  ADC  AL  APD  AYR )
> IB::Symbols.allocate_collection :w20                               => IB::Symbols::W20 
> symbols.each_with_index{ |s,i| IB::Symbols::W20.add_contract i, IB::Stock.new( symbol: s ) }
> IB::Symbols::W20.size                                              => 19

Sequential Access to Market Prices

Because the IB::Symbols-Enumerator yields IB::Contract's its just possible to fetch market prices sequentially by traversing though the elements of the Enumerator.

 # first filter invalid symbols via Contract.verify
 prices = IB::Symbols::W20.map {|s| s.verify.first &.market_price } 
 => [nil, 24.97, nil, 4.73, nil, 59.0, nil, 48.35, nil, 165.93, 56.82, 4.2, 138.72, 137.54, 71.7, 69.77, 47.08, 298.28, nil] 
 # non existing stocks are omitted 
> Symbols::W20.map( &:symbol ).zip( prices ).to_h
 => {"ANW"=>nil,  "AEB"=>24.97, "AED"=>nil,    "AEG"=>4.73, "AEH"=>nil, 
     "AER"=>59.0, "HIVE"=>nil,  "AJRD"=>48.35, "AET"=>nil,  "AMG"=>165.93, 
		 "AFL"=>56.82,"MITT"=>4.2,  "AGCO"=>138.72,"A"=>137.54, "AEM"=>71.7, 
		 "ADC"=>69.77,"AL"=>47.08,  "APD"=>298.28, "AYR"=>nil} 

In an experiment on a public holiday, it took 105 seconds to fetch the data for just 19 IB::Contracts. This is not acceptable.

Asynchronous Access

The alternative approach: fire the :RequestMarketData messages for all contract at once and wait for the response.

IB::Contract.market_price has a threaded-modus, which collects data in background.

 start = Time.now;
 # the parameter no_error prevents interrupts in case the symbol does not exists 
 prices = Symbols::W20.map{|x| x.market_price(thread: true, no_error: true )}.each( &:join);
 puts "eclipsed Time: #{Time.now - start }"         ==> eclipsed Time: 5.206946497
 Symbols::W20.map{ |s| [s.symbol , s.misc.values.first  ] }.to_h
 => {"ANW"=>nil,  "AEB"=>24.97, "AED"=>nil,    "AEG"=>4.73, "AEH"=>nil, 
     "AER"=>59.0, "HIVE"=>nil,  "AJRD"=>48.35, "AET"=>nil,  "AMG"=>165.93, 
		 "AFL"=>56.82,"MITT"=>4.2,  "AGCO"=>138.72,"A"=>137.54, "AEM"=>71.7, 
		 "ADC"=>69.77,"AL"=>47.08,  "APD"=>298.28, "AYR"=>nil} 

Definitively an improvement!

In threaded mode the method fires all :RequestMarketData messages at once and then waits for the TWS to respond.

The approach has the disadvantage, that the thread itself has to be returned. If thread: true is specified the fetched market-price is stored in IB::Contract.misc, raw-data are still present in IB::Contract.bars.

```

Tags: