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: