Class: TechnicalAnalysis::Rsi

Inherits:
Indicator show all
Defined in:
lib/technical_analysis/indicators/rsi.rb

Overview

Relative Strength Index

Class Method Summary collapse

Methods inherited from Indicator

find, roster

Class Method Details

.calculate(data, period: 14, price_key: :value, date_time_key: :date_time) ⇒ Array<RsiValue>

Calculates the relative strength index for the data over the given period en.wikipedia.org/wiki/Relative_strength_index

Parameters:

  • data (Array)

    Array of hashes with keys (:date_time, :value)

  • period (Integer) (defaults to: 14)

    The given period to calculate the RSI

  • price_key (Symbol) (defaults to: :value)

    The hash key for the price data. Default :value

  • date_time_key (Symbol) (defaults to: :date_time)

    The hash key for the date time data. Default :date_time

Returns:

  • (Array<RsiValue>)

    An array of RsiValue instances

[View source]

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/technical_analysis/indicators/rsi.rb', line 54

def self.calculate(data, period: 14, price_key: :value, date_time_key: :date_time)
  period = period.to_i
  price_key = price_key.to_sym
  Validation.validate_numeric_data(data, price_key)
  Validation.validate_length(data, min_data_size(period: period))
  Validation.validate_date_time_key(data, date_time_key)

  data = data.sort_by { |row| row[date_time_key] }

  output = []
  prev_price = data.shift[price_key]
  prev_avg = nil
  price_changes = []
  smoothing_period = period - 1

  data.each do |v|
    price_change = (v[price_key] - prev_price)
    price_changes << price_change

    if price_changes.size == period
      if prev_avg.nil?
        avg_gain = ArrayHelper.average(price_changes.map { |pc| pc.positive? ? pc : 0 })
        avg_loss = ArrayHelper.average(price_changes.map { |pc| pc.negative? ? pc.abs : 0 })
      else
        if price_change > 0
          current_loss = 0
          current_gain = price_change
        elsif price_change < 0
          current_loss = price_change.abs
          current_gain = 0
        else
          current_loss = 0
          current_gain = 0
        end

        avg_gain = (((prev_avg[:gain] * smoothing_period) + current_gain) / period.to_f)
        avg_loss = (((prev_avg[:loss] * smoothing_period) + current_loss) / period.to_f)
      end

      if avg_loss == 0
        rsi = 100
      else
        rs = avg_gain / avg_loss
        rsi = (100.00 - (100.00 / (1.00 + rs)))
      end

      output << RsiValue.new(date_time: v[date_time_key], rsi: rsi)

      prev_avg = { gain: avg_gain, loss: avg_loss }
      price_changes.shift
    end

    prev_price = v[price_key]
  end

  output.sort_by(&:date_time).reverse
end

.indicator_nameString

Returns the name of the technical indicator

Returns:

  • (String)

    A string of the name of the technical indicator

[View source]

15
16
17
# File 'lib/technical_analysis/indicators/rsi.rb', line 15

def self.indicator_name
  "Relative Strength Index"
end

.indicator_symbolString

Returns the symbol of the technical indicator

Returns:

  • (String)

    A string of the symbol of the technical indicator

[View source]

8
9
10
# File 'lib/technical_analysis/indicators/rsi.rb', line 8

def self.indicator_symbol
  "rsi"
end

.min_data_size(period: 14, **params) ⇒ Integer

Calculates the minimum number of observations needed to calculate the technical indicator

Parameters:

  • options (Hash)

    The options for the technical indicator

Returns:

  • (Integer)

    Returns the minimum number of observations needed to calculate the technical indicator based on the options provided

[View source]

41
42
43
# File 'lib/technical_analysis/indicators/rsi.rb', line 41

def self.min_data_size(period: 14, **params)
  period.to_i + 1
end

.valid_optionsArray

Returns an array of valid keys for options for this technical indicator

Returns:

  • (Array)

    An array of keys as symbols for valid options for this technical indicator

[View source]

22
23
24
# File 'lib/technical_analysis/indicators/rsi.rb', line 22

def self.valid_options
  %i(period price_key date_time_key)
end

.validate_options(options) ⇒ Boolean

Validates the provided options for this technical indicator

Parameters:

  • options (Hash)

    The options for the technical indicator to be validated

Returns:

  • (Boolean)

    Returns true if options are valid or raises a ValidationError if they’re not

[View source]

31
32
33
# File 'lib/technical_analysis/indicators/rsi.rb', line 31

def self.validate_options(options)
  Validation.validate_options(options, valid_options)
end