Module: StochasticOscillator

Included in:
Array
Defined in:
lib/ruby-technical-analysis/indicators/stochastic_oscillator.rb

Overview

Stochastic Oscillator indicator Returns a single value

Instance Method Summary collapse

Instance Method Details

#stochastic_oscillator(k_periods, k_slow_periods, d_periods) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/ruby-technical-analysis/indicators/stochastic_oscillator.rb', line 6

def stochastic_oscillator(k_periods, k_slow_periods, d_periods)
  highs = []
  lows = []
  closes = []

  each do |i|
    highs << i[0]
    lows << i[1]
    closes << i[2]
  end

  if highs.size < k_periods
    raise ArgumentError,
          "High array passed to Stochastic Oscillator cannot be less than the k_periods argument."
  end

  if lows.size < k_periods
    raise ArgumentError,
          "Low array passed to Stochastic Oscillator cannot be less than the k_periods argument."
  end

  if closes.size < k_periods
    raise ArgumentError,
          "Close array passed to Stochastic Oscillator cannot be less than the k_periods argument."
  end

  lowest_lows = []
  highest_highs = []
  close_minus_ll = []
  hh_minus_ll = []

  ks_sums_close_min_ll = []
  ks_sums_hh_min_ll = []
  ks_div_x_100 = []
  d_periods_sma = []

  (0..(highs.length - k_periods)).each do |i|
    lowest_lows << lows[i..(i + k_periods - 1)].min
    highest_highs << highs[i..(i + k_periods - 1)].max
    close_minus_ll << (closes[i + k_periods - 1] - lowest_lows.last).round(4)
    hh_minus_ll << (highest_highs.last - lowest_lows.last).round(4)
    if close_minus_ll.length >= k_slow_periods
      ks_sums_close_min_ll << close_minus_ll.last(k_slow_periods).inject(:+).round(4)
      ks_sums_hh_min_ll << hh_minus_ll.last(k_slow_periods).inject(:+).round(4)
      ks_div_x_100 << ((ks_sums_close_min_ll.last.to_f / ks_sums_hh_min_ll.last) * 100).round(4)
    end
    d_periods_sma << if ks_div_x_100.length >= d_periods
                       (ks_div_x_100.last(d_periods).reduce(:+).to_f / d_periods).round(4)
                     else
                       -1000
                     end
  end

  d_periods_sma[-1]
end