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:



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

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



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

def self.valid_intervals
  INTERVAL_DISTANCE.keys
end

Instance Method Details

#==(other) ⇒ Object



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

def ==(other)
  interval == other&.interval
end

#durationObject Also known as: seconds



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

def duration
  INTERVAL_DISTANCE[interval]
end

#half_lifeObject



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

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



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

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



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

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



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

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

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



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

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