Class: Quant::Interval

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

Overview

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 Ticks::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.



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

def initialize(interval)
  ensure_valid_interval!(interval)

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

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



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

def interval
  @interval
end

Class Method Details

.[](value) ⇒ Object

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



130
131
132
133
134
# File 'lib/quant/interval.rb', line 130

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

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

.all_resolutionsObject

Returns the full list of valid resolution Strings that can be used to instantiate an Quant::Interval.



216
217
218
# File 'lib/quant/interval.rb', line 216

def self.all_resolutions
  RESOLUTIONS.keys
end

.ensure_valid_resolution!(resolution) ⇒ Object



233
234
235
236
237
238
# File 'lib/quant/interval.rb', line 233

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

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

.from_mappings(value) ⇒ Object

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



137
138
139
140
141
142
# File 'lib/quant/interval.rb', line 137

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 Quant::Interval.



122
123
124
125
126
# File 'lib/quant/interval.rb', line 122

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

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

.valid_intervalsObject

Returns the full list of valid interval Strings that can be used to instantiate an Quant::Interval.



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

def self.valid_intervals
  INTERVAL_DISTANCE.keys
end

Instance Method Details

#==(other) ⇒ Object

Compares the interval to another interval, string, or symbol and returns true if they are equal.



174
175
176
177
178
179
180
181
182
# File 'lib/quant/interval.rb', line 174

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

Returns the total span of seconds or duration for the interval.

Examples:

Quant::Interval.new("1d").duration => 86400
Quant::Interval.new("1h").duration => 3600
Quant::Interval.new("1m").duration => 60
Quant::Interval.new("1s").duration => 1
Quant::Interval.new("na").duration => 0


168
169
170
# File 'lib/quant/interval.rb', line 168

def duration
  INTERVAL_DISTANCE[interval]
end

#half_lifeObject

Returns the half-life of the interval in seconds.

Examples:

Quant::Interval.new("1d").half_life => 43200.0
Quant::Interval.new("1h").half_life => 1800.0
Quant::Interval.new("1m").half_life => 30.0


199
200
201
# File 'lib/quant/interval.rb', line 199

def half_life
  duration / 2.0
end

#next_intervalObject

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



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

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

#nil?Boolean

Returns true when the duration of the interval is zero, such as for the ‘na` interval.

Returns:

  • (Boolean)


153
154
155
# File 'lib/quant/interval.rb', line 153

def nil?
  duration.zero?
end

#ticks_per_minuteObject

Returns the number of ticks this interval represents per minute.

Examples:

Quant::Interval.new("1d").ticks_per_minute => 0.0006944444444444445
Quant::Interval.new("1h").ticks_per_minute => 0.016666666666666666
Quant::Interval.new("1m").ticks_per_minute => 1.0
Quant::Interval.new("1s").ticks_per_minute => 60.0


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

def ticks_per_minute
  60.0 / seconds
end

#ticks_to(timestamp) ⇒ Object

Computes the number of ticks from present to given timestamp. If timestamp doesn’t cover a full interval, it will be rounded up to 1

Examples:

interval = Quant::Interval.new("1d")
interval.ticks_to(Time.now + 5.days) # => 5  NOTE: `5.days` is an ActiveSupport method


225
226
227
# File 'lib/quant/interval.rb', line 225

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

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



229
230
231
# File 'lib/quant/interval.rb', line 229

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

#to_sObject



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

def to_s
  interval
end