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.



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



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

def self.ensure_valid_resolution!(resolution)
  return if RESOLUTIONS.keys.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.



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

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



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

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.



178
179
180
181
182
183
184
185
186
# File 'lib/quant/interval.rb', line 178

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


172
173
174
# File 'lib/quant/interval.rb', line 172

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


203
204
205
# File 'lib/quant/interval.rb', line 203

def half_life
  duration / 2.0
end

#next_intervalObject

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



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

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)


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

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


194
195
196
# File 'lib/quant/interval.rb', line 194

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


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

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

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



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

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

#to_sObject



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

def to_s
  interval
end