Module: Coinbot::OrderBook::RSI

Defined in:
lib/coinbot/order_book/rsi.rb

Class Method Summary collapse

Class Method Details

.calculate(opts = {}) ⇒ Object

Supported Method Parameters

Coinbot::OrderBook::RSI.calculate(

order_book: 'required - order book data structure'

)



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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/coinbot/order_book/rsi.rb', line 77

public_class_method def self.calculate(opts = {})
  # Relative Strength Index (RSI) ALGORITHM
  last_ticker_price = opts[:last_ticker_price].to_f
  candles = opts[:candles]
  rsi_history = opts[:rsi_history]
  rsi_candle = 14

  # We only need 13 candles closed as the 14th
  # leverages current ticker price.
  return rsi_history.push('--') if candles.length < rsi_candle

  # step 1
  # Calculate the bar-to-bar changes for each bar
  # This is change = candle close - previous candle close
  # If the change is positive, add it to gains_arr
  # If the change is negative or zero, add 0 to gains_arr
  # If the change is negative, add absolute value of change to loss_arr
  # If the change is positive or zero, add 0 to loss_arr

  gain_arr = []
  loss_arr = []

  candles.last(rsi_candle)[..-2].map do |in_scope|
    candle_close = in_scope[:candle_close].to_f
    candle_open = in_scope[:candle_open].to_f
    candle_price_diff = candle_close - candle_open
    gain_arr.push(candle_price_diff) if candle_price_diff.positive?
    gain_arr.push(0) if candle_price_diff.negative? ||
                        candle_price_diff.zero?

    loss_arr.push(candle_price_diff.abs) if candle_price_diff.negative?
    loss_arr.push(0) if candle_price_diff.positive? ||
                        candle_price_diff.zero?
  end

  # Last Candle w/ Current Ticker Data
  last_candle_open = candles.last[:candle_open].to_f
  last_candle_price_diff = last_ticker_price - last_candle_open

  gain_arr.push(last_candle_price_diff) if last_candle_price_diff.positive?
  gain_arr.push(0) if last_candle_price_diff.negative? ||
                      last_candle_price_diff.zero?

  loss_arr.push(last_candle_price_diff.abs) if last_candle_price_diff.negative?
  loss_arr.push(0) if last_candle_price_diff.positive? ||
                      last_candle_price_diff.zero?

  # step 2
  # Calculate the average gain and average loss
  # This can be done using several methods
  # We'll use Wilders smoothing method

  first_avg_gain = gain_arr.sum / rsi_candle
  first_avg_loss = loss_arr.sum / rsi_candle

  avg_gain = ((first_avg_gain * 13) + gain_arr.last) / rsi_candle
  avg_loss = ((first_avg_loss * 13) + loss_arr.last) / rsi_candle

  # step 3 and 4
  # Calculate the Relative Strength and the Relative Strength Index (RSI)
  # What situation in the market would give us the maximum possible RSI value?
  # This would be a totally bullish market with no down days.
  # AvgD would be zero, AvgU some positive number.
  # Relative Strength would be something positive divided by zero.
  # Mathematically, you cannot calculate this. In this case the RSI value is defined as 100.
  if avg_loss.zero?
    # avg_loss was 0.0 resulting in avg_gain / 0.0 = Float::INFINITY
    rsi = format('%0.2f', 100)
  else
    rs = avg_gain / avg_loss
    rsi = format('%0.2f', 100 - (100 / (1 + rs)))
  end

  rsi_hash = {
    time: Time.now.strftime('%Y-%m-%d %H:%M:%S.%N%z'),
    rsi: rsi
  }
  rsi_history.push(rsi_hash)

  # Retain a sane amount of history
  rsi_hist_retention = 900
  if rsi_history.length >= rsi_hist_retention
    # [retain_history..] << Not a typo - equivalent to
    # [retain_record..-1]
    retain_record = rsi_hist_retention * -1
    rsi_hist_arr = rsi_history[retain_record..]
    rsi_history = rsi_hist_arr
  end

  rsi_history
rescue StandardError => e
  raise "#{e} RSI_HISTORY: #{rsi_history.inspect}"
end

.helpObject

Display Usage for this Module



173
174
175
176
177
# File 'lib/coinbot/order_book/rsi.rb', line 173

public_class_method def self.help
  puts "USAGE:
   golden_cross_indicator_hash = #{self}.status()
  "
end

.status(opts = {}) ⇒ Object

Supported Method Parameters

Coinbot::OrderBook::RSI.status( )



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
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/coinbot/order_book/rsi.rb', line 12

public_class_method def self.status(opts = {})
  indicator_status = opts[:indicator_status]
  rsi_history = opts[:rsi_history]
  candles = opts[:candles]
  invested = opts[:invested]
  bot_conf = opts[:bot_conf]

  max_rsi_to_buy = bot_conf[:weights][:rsi][:max_rsi_to_buy].to_f

  indicator_hash = {}
  indicator_hash[:invested] = invested
  indicator_hash[:status] = 'RSI'

  return unless rsi_history.length > 1

  # If -- to_f will cast as 0.0
  # raise rsi_history.inspect
  # uniq_rsi_hist = rsi_history.uniq { |h| h[:rsi] }
  uniq_rsi_hist = rsi_history.uniq

  return if uniq_rsi_hist.last == '--'

  last_rsi = uniq_rsi_hist.last[:rsi] if uniq_rsi_hist.length == 1 &&
                                         candles.length == 1

  last_rsi = candles[-2][:rsi_history].last[:rsi] if uniq_rsi_hist.length == 1 &&
                                                     candles.length > 1

  last_rsi = uniq_rsi_hist[-2][:rsi] if uniq_rsi_hist.length > 1 &&
                                        candles.length > 1

  rsi = uniq_rsi_hist.last[:rsi]

  indicator_hash[:color] = :white

  # if rsi != '--'
  if rsi != '--' && last_rsi != '--'
    indicator_hash[:color] = :green if rsi.to_f.positive? &&
                                       rsi.to_f > last_rsi.to_f

    # indicator_hash[:color] = :green if rsi.to_f.positive? &&
    #                                    rsi.to_f < max_rsi_to_buy

    indicator_hash[:color] = :yellow if rsi.to_f.positive? &&
                                        rsi.to_f == last_rsi.to_f

    indicator_hash[:color] = :red if rsi.to_f.positive? && (
                                       rsi.to_f < last_rsi.to_f ||
                                       rsi.to_f >= max_rsi_to_buy
                                     )

    # indicator_hash[:color] = :red if rsi.to_f.positive? &&
    #                                  rsi.to_f >= max_rsi_to_buy

  end

  indicator_status.rsi = indicator_hash
rescue StandardError => e
  raise e
end