Class: Quant::Interval

Inherits:
Object
  • Object
show all
Defined in:
lib/quant/interval.rb

Overview

Quant::Interval abstracts away the concept of ticks (candles, bars, etc.) and their duration and offers some basic utilities for working with multiple timeframes. Intervals are used in Tick and Series classes to define the duration of the ticks.

When the Interval is unknown, it is set to ‘na’ (not available) and the duration is set to 0. The shorthand for this is Interval.na. and Interval[:na]. and Interval[nil].

Interval are instantiated in multple ways to support a wide variety of use-cases. Here’s an example:

Quant::Interval.new("1d")               # => #<Quant::Interval @interval="1d"> (daily interval)
Quant::Interval.new(:daily)             # => #<Quant::Interval @interval="1d">
Quant::Interval[:daily]                 # => #<Quant::Interval @interval="1d">
Quant::Interval.from_resolution(60)     # => #<Quant::Interval @interval="1h">
Quant::Interval.from_resolution("1D")   # => #<Quant::Interval @interval="1d">
Quant::Interval.from_resolution("D")    # => #<Quant::Interval @interval="1d">

Intervals have a number of useful methods:

interval = Quant::Interval.new("1d")     # => #<Quant::Interval @interval="1d">  (daily interval)
interval.nil?                            # => false
interval.duration                        # => 86400
interval.ticks_per_minute                # => 0.0006944444444444445
interval.half_life                       # => 43200.0
interval.next_interval                   # => #<Quant::Interval @interval="1w"> (weekly interval)

When you don’t wish to specify an interval or it is unknown, you can use the na interval:

interval = Quant::Interval.na           # => #<Quant::Interval @interval="na">
interval.nil?                           # => true
interval.duration                       # => 0

Constant Summary collapse

MAPPINGS =
{
  na:               { interval: "na",   distance: 0 },
  second:           { interval: "1s",   distance: 1 },
  two_seconds:      { interval: "2s",   distance: 2 },
  three_seconds:    { interval: "3s",   distance: 3 },
  five_seconds:     { interval: "5s",   distance: 5 },
  ten_seconds:      { interval: "10s",  distance: 10 },
  fifteen_seconds:  { interval: "15s",  distance: 15 },
  thirty_seconds:   { interval: "30s",  distance: 30 },
  minute:           { interval: "1m",   distance: 60 },
  one_minute:       { interval: "1m",   distance: 60 },
  three_minutes:    { interval: "3m",   distance: 60 * 3 },
  five_minutes:     { interval: "5m",   distance: 60 * 5 },
  fifteen_minutes:  { interval: "15",   distance: 60 * 15 },
  thirty_minutes:   { interval: "30",   distance: 60 * 30 },
  hour:             { interval: "1h",   distance: 60 * 60 },
  two_hours:        { interval: "2h",   distance: 60 * 60 * 2 },
  four_hours:       { interval: "4h",   distance: 60 * 60 * 4 },
  eight_hours:      { interval: "8h",   distance: 60 * 60 * 8 },
  twelve_hours:     { interval: "12h",  distance: 60 * 60 * 12 },
  daily:            { interval: "1d",   distance: 60 * 60 * 24 },
  weekly:           { interval: "1w",   distance: 60 * 60 * 24 * 7 },
  monthly:          { interval: "1M",   distance: 60 * 60 * 24 * 30 },
}.freeze
INTERVAL_DISTANCE =
MAPPINGS.values.map { |v| [v[:interval], v[:distance]] }.to_h.freeze
RESOLUTIONS =
{
  "1"   => :one_minute,
  "3"   => :three_minutes,
  "5"   => :five_minutes,
  "15"  => :fifteen_minutes,
  "30"  => :thirty_minutes,
  "60"  => :hour,
  "240" => :four_hours,
  "D"   => :daily,
  "1D"  => :daily,
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(interval) ⇒ Interval

Returns a new instance of Interval.



150
151
152
153
154
# File 'lib/quant/interval.rb', line 150

def initialize(interval)
  ensure_valid_interval!(interval)

  @interval = (interval || "na").to_s
end

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



148
149
150
# File 'lib/quant/interval.rb', line 148

def interval
  @interval
end

Class Method Details

.[](value) ⇒ Object

Instantiates an Interval from a string or symbol. If the value is already an Interval, it is returned as-is.



134
135
136
137
138
# File 'lib/quant/interval.rb', line 134

def self.[](value)
  return value if value.is_a? Interval

  from_mappings(value) || Interval.new(value)
end

.all_resolutionsObject



119
120
121
# File 'lib/quant/interval.rb', line 119

def self.all_resolutions
  RESOLUTIONS.keys
end

.ensure_valid_resolution!(resolution) ⇒ Object

Raises:



209
210
211
212
213
# File 'lib/quant/interval.rb', line 209

def self.ensure_valid_resolution!(resolution)
  return if RESOLUTIONS.keys.include? resolution

  raise InvalidResolution, "resolution (#{resolution}) not a valid resolution. Should be one of: (#{RESOLUTIONS.keys.join(", ")})"
end

.from_mappings(value) ⇒ Object

Looks up the given mapping (i.e. :daily) and returns the Interval for that mapping.



141
142
143
144
145
146
# File 'lib/quant/interval.rb', line 141

def self.from_mappings(value)
  mapping = MAPPINGS[value&.to_sym]
  return unless mapping

  Interval.new(mapping[:interval])
end

.from_resolution(resolution) ⇒ Object

Instantiates an Interval from a resolution. For example, TradingView uses resolutions like “1”, “3”, “5”, “15”, “30”, “60”, “240”, “D”, “1D” to represent the duration of a candlestick. from_resolution translates resolutions to the appropriate Interval.



126
127
128
129
130
# File 'lib/quant/interval.rb', line 126

def self.from_resolution(resolution)
  ensure_valid_resolution!(resolution)

  Interval.new(MAPPINGS[RESOLUTIONS[resolution]][:interval])
end

.valid_intervalsObject



196
197
198
# File 'lib/quant/interval.rb', line 196

def self.valid_intervals
  INTERVAL_DISTANCE.keys
end

Instance Method Details

#==(other) ⇒ Object



169
170
171
172
173
174
175
176
177
# File 'lib/quant/interval.rb', line 169

def ==(other)
  if other.is_a? String
    interval.to_s == other
  elsif other.is_a? Symbol
    interval == MAPPINGS[other]&.fetch(:interval, nil)
  else
    interval == other&.interval
  end
end

#durationObject Also known as: seconds



164
165
166
# File 'lib/quant/interval.rb', line 164

def duration
  INTERVAL_DISTANCE[interval]
end

#half_lifeObject



183
184
185
186
187
# File 'lib/quant/interval.rb', line 183

def half_life
  raise "bad interval #{interval}" if duration.nil?

  duration / 2.0
end

#next_intervalObject

Returns the Interval for the next higher timeframe. For example, hourly -> daily -> weekly -> monthly



191
192
193
194
# File 'lib/quant/interval.rb', line 191

def next_interval
  intervals = INTERVAL_DISTANCE.keys
  Interval.new intervals[intervals.index(interval) + 1] || intervals[-1]
end

#nil?Boolean

Returns:

  • (Boolean)


156
157
158
# File 'lib/quant/interval.rb', line 156

def nil?
  interval == "na"
end

#ticks_per_minuteObject



179
180
181
# File 'lib/quant/interval.rb', line 179

def ticks_per_minute
  60.0 / seconds
end

#ticks_to(timestamp) ⇒ Object

NOTE: if timestamp doesn’t cover a full interval, it will be rounded up to 1



201
202
203
# File 'lib/quant/interval.rb', line 201

def ticks_to(timestamp)
  ((timestamp - Quant.current_time) / duration).round(2).ceil
end

#timestamp_for(ticks:, timestamp: Quant.current_time) ⇒ Object



205
206
207
# File 'lib/quant/interval.rb', line 205

def timestamp_for(ticks:, timestamp: Quant.current_time)
  timestamp + (ticks * duration)
end

#to_sObject



160
161
162
# File 'lib/quant/interval.rb', line 160

def to_s
  interval
end