To use the End of Data Historical Data feature activate the eod plugin
 
require 'ib-api' 
ib =  IB::Connection.new
ib.activate_plugin :eod
ib.try_connection!
Stock.new(symbol: :sie, currency: :eur).eod.to_human
<Bar (10.07.24)00:00:00 
 wap 175.522 
 OHLC 173.48 177.24 170.66 176.38 
 trades 20807 
 vol 1302308>

Historical Data

The historical data feature of the TWS is invoked by sending a :RequestHistoricalData-Message.
Next the script has to listen for a :HistoricalData-Response.

The IB::Contract.eod-method bundles the necessary steps to get End of Day-Data for specified date ranges.

  • contract.eod( duration: '10 d' ) gets closing price of the last 10 trading days.
  • contract.eod( duration: '10 w', start: Date.new(2019,3,14), what: :historical_volatility ) gets the historical volatility for the 10 weeks starting on March 14th 2019.

IB::Contract.eod start: {a date}, to: {a date; Default: Date.today},
                 duration: {string  or integer},
                 what: {symbol; Default: :trades }

The duration can either be specified as Sting “ yx D”, “ yx W”, “yx M” , “xy Y” or as Integer. If the string-notation is used, ensure to include a space.

The parameter :what specifies the kind of received data.

Valid values:

  • :trades, :midpoint, :bid, :ask, :bid_ask,
  • :historical_volatility, :option_implied_volatility,
  • :option_volume, :option_open_interest

IB::Contract.eod returns an array of IB::Bar objects unless they are preprocessed in a block.

thus

> puts Symbols::Futures.mini_dax.eod( duration: 10 ).as_table
┌─────┬────────────┬─────────┬─────────┬─────────┬─────────┬────────┬─────────┬────────┐
 Bar  time        open     high     low      close    volume  wap      trades 
╞═════╪════════════╪═════════╪═════════╪═════════╪═════════╪════════╪═════════╪════════╡
 Bar  2024-06-27  18300.0  18438.0  18259.0  18369.0  23372   18369.5  14833  
 Bar  2024-06-28  18417.0  18526.0  18360.0  18403.0  28560   18436.0  18065  
 Bar  2024-07-01  18471.0  18632.0  18427.0  18490.0  30485   18512.4  19796  
 Bar  2024-07-02  18487.0  18487.0  18190.0  18315.0  33725   18313.0  20378  
 Bar  2024-07-03  18348.0  18569.0  18348.0  18547.0  26490   18470.9  16228  
 Bar  2024-07-04  18575.0  18628.0  18546.0  18609.0  14495   18593.2  9090   
 Bar  2024-07-05  18602.0  18821.0  18572.0  18614.0  30408   18693.9  18529  
 Bar  2024-07-08  18563.0  18784.0  18563.0  18645.0  22899   18678.4  14291  
 Bar  2024-07-09  18637.0  18656.0  18361.0  18369.0  29256   18493.6  18122  
 Bar  2024-07-10  18411.0  18611.0  18371.0  18566.0  21611   18489.1  13335  
└─────┴────────────┴─────────┴─────────┴─────────┴─────────┴────────┴─────────┴────────┘

Export to Polars Dataframes

If »polars: true« is specified in the method call the response is stored as PolarsDataframe.

For further processing: https://github.com/ankane/polars-ruby
https://pola-rs.github.io/polars/py-polars/html/index.html

 > puts  Stock.new( symbol: :iwm ).eod( start: Date.new(2019,10,9), duration: 3, polars: true )
 => shape: (3, 8)
 ┌────────────┬────────┬────────┬────────┬────────┬────────┬─────────┬────────┐
  time        open    high    low     close   volume  wap      trades 
  ---         ---     ---     ---     ---     ---     ---      ---    
  date        f64     f64     f64     f64     i64     f64      i64    
 ╞════════════╪════════╪════════╪════════╪════════╪════════╪═════════╪════════╡
  2019-10-08  148.62  149.37  146.11  146.45  156625  146.831  88252  
  2019-10-09  147.18  148.0   145.38  145.85  94337   147.201  51294  
  2019-10-10  146.9   148.74  146.87  148.24  134549  147.792  71084  
 └────────────┴────────┴────────┴────────┴────────┴────────┴─────────┴────────┘

Examples

  • Retrieve close prices of the last ten days.
IB::Symbols::Index.stoxx.eod( duration: '10 d' ){ |r| r.close  }
  • Get price-ranges of the last ten days.
IB::Symbols::Index.stoxx.eod( duration: '10 d' ){ |r| r.high - r.low  }
  • Get close prices for General Electric between Jun 15 and Jun 21 2015
 IB::Stock.new( symbol: 'GE' ).
           eod( start: Date.new(2015,6,15), to: Date.new(2015,6,21) ).
           map( &:close ).
           join( " : " )
 => "26.19 : 26.17 : 26.24 : 26.18"
  • Get Overnight Gaps for the stock
 yesterdays_close = nil
 IB::Stock.new( symbol: 'GE').
           eod( start: Date.new(2010,6,15), duration: 10 ) do |r|
                  z= if  yesterdays_close.nil? 
                         0
                     else 
                         (yesterdays_close - r.open).abs
                     end
                  yesterdays_close = r.close 
                  z        #   return value 
          end.join( " : " )
=> "0 : 0.08 : 0.02 : 0.0 : 0.01 : 0.03 : 0.03 : 0.1 : 0.04 : 0.03" 

We save the close of each day in yesterdays_close and pass it to the next iteration. yesterdays_close has to be declared outside of the block!

  • Get the daily median of Implied Volatilities
 ge = IB::Stock.new symbol: :ge
 ge.eod( duration: 10, what: :option_implied_volatility){|x| (x.high + x.low)/2 }.round 3
=> [0.434, 0.425, 0.437, 0.442, 0.441, 0.436, 0.491, 0.491, 0.491, 0.494] 

  • Save historical data as csv file
 # reopen IB::Contract and add to_csv method
 module IB
   class Contract 
     def to_csv file:nil
       file ||=  "#{symbol}.csv"
       if bars.present?
         headers = bars.first.invariant_attributes.keys
         CSV.open( file, 'w'  ) {|f| f << headers ; bars.each {|y| f << y.invariant_attributes.values } }
      end
    end
  end
 end

 ge = IB::Stock.new( symbol: :ge  )
 ge.eod( duration: '200 D' )
 ge.to_csv         # writes ohlc-data to ge.csv

Tags: