Method: TechnicalAnalysis::Dpo.calculate

Defined in:
lib/technical_analysis/indicators/dpo.rb

.calculate(data, period: 20, price_key: :value) ⇒ Array<DpoValue>

Calculates the detrended price oscillator for the data over the given period en.wikipedia.org/wiki/Detrended_price_oscillator

Parameters:

  • data (Array)

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

  • period (Integer) (defaults to: 20)

    The given period to calculate the SMA

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

    The hash key for the price data. Default :value

Returns:



53
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
# File 'lib/technical_analysis/indicators/dpo.rb', line 53

def self.calculate(data, period: 20, price_key: :value)
  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)

  data = data.sort_by { |row| row[:date_time] }

  index = period + (period / 2) - 1
  midpoint_index = (period / 2) + 1
  output = []

  while index < data.size
    current_record = data[index]
    date_time = current_record[:date_time]
    current_price = current_record[price_key]

    sma_range = (index - midpoint_index - period + 2)..(index - midpoint_index + 1)
    midpoint_period_sma = ArrayHelper.average(data[sma_range].map { |v| v[price_key] })

    dpo = (current_price - midpoint_period_sma)

    output << DpoValue.new(date_time: date_time, dpo: dpo)

    index += 1
  end

  output.sort_by(&:date_time).reverse
end