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