From 990d5097ce5fdefc3a864eaba8195312ae54c79c Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Jan 2019 15:54:27 -0500 Subject: [PATCH 01/84] First wave of technical indicators (#34) * Start of ADI indicator * Updated SMA and ADI to use new input/output data format (array of hashes). Spec helpers to use CSV sample data. Updated SMA and ADI specs to use new sample data. Data sort helpers. Validation updates. * Updated yard comments * Remove /calculate * Add Stochastic Oscillator - Require in main technical_analysis - Create calculation - Create spec * Add Stochastic Oscillator Signal (%D) - Update main technical_analysis to require sr_signal - Create calculation - Create spec * Add Awesome Oscillator - Update technical_analysis to require AO - Create calculation - Create spec * Add Ultimate Oscillator - Add require uo to technical_analysis - Create calculation - Create spec * Create Williams %R - Add require wr to technical_analysis - Create calculation - Create spec * Create ADTV - Average Daily Trading Volume - Add require 'adtv' to technical_analysis - Create calculation - Create spec * Create OBV Mean - On-balance volume mean - Add require 'obv_mean' to technical_analysis - Create calculation - Create spec * Change price_key to volume_key for clarity * Create OBV - On-balance volume - Add require 'obv' to technical_analysis - Create calculation - Create spec * Create CR - Cumulative Return - Add require 'cr' to technical_analysis - Create calculation - Create spec * Add validator to make sure data exists * Add DLR - Daily Log Return - Add require 'dlr' to technical_analysis - Create calculation - Create spec * Add DR - Daily Return - Add require 'dr' to technical_analysis - Create calculation - Create spec * Add TSI - True Strength Index - Add require 'tsi' to technical_analysis - Create calculation - create spec * Add RSI - Relative Strength Index - Add require 'rsi' to technical_analysis - Create calculation - Create spec * Add MFI - Money Flow Index - Add require 'mfi' to technical_analysis - Create calculation - Create spec * Add Ichimoku - Add require 'ichimoku' to technical_analysis - Create calculation - Create spec * Move response inside value key * Add KST - Known Sure Thing - Add require 'kst' to technical_analysis - Create calculation - Create spec * Add DSO - Detrended Price Oscillator - Add require 'dso' to technical_analysis - Create calculation - Create spec * Add CCI - Commodity Channel Index - Add require 'cci' to technical_analysis - Create calculation - Create spec * Add MI - Mass Index - Add require 'mi' to technical_analysis - Create calculation - Create spec * Add Trix - Triple Exponential Average - Add require 'trix' to technical_analysis - Create calculation - Create spec * Refactor * Add VI - Vortex Indicator - Add require 'vi' to technical_analysis - Create caluclation - Create spec * Refactor * Refactor - merge SR and SR signal into one calc * Refactor calculation * Update logic for validating data size * Refactor calculation * Remove a puts...oops! * Refactor calculation * Removed old/unused variable * Refactor calculation and fix spec * More trimming * Remove select(&:) / refactor * Refactor * Add ADX - Average Directional Index - Add require 'adx' to technical_analysis - Create calculation - Create spec * Add FI - Force Index - Add require 'fi' to technical_analysis - Create calculation - Create spec * Add VPT - Volume-Price Trent - Add require 'vpt' to technical_analysis - Create calculation - Create spec * Add CMF - Chaikin Money Flow - Add require 'cmf' to technical_analysis - Create calculation - Create spec * Add EoM / EVM - Ease of Movement - Add require 'eom' and 'evm' to technical_analysis - Create calculation for Eom and reference it in Evm - Create specs for Eom and Evm * Update yard comments to remove reference to period * Update yard comments to remove reference to period. * Add NVI - Negative Volume Index - Add require 'nvi' to technical_analysis - Create calculation - Create spec * Add ATR - Average True Range - Add require 'atr' to technical_analysis - Create calculation - Create spec * Don't count first record - To make the true range calculation consistent with other indicators, don't count a true range for the first record. * Refactor true range calculation to be more legible * Add BB - Bollinger Bands - Add require 'bb' to technical_analysis - Create calculation - Create spec - Add methods to array helper: - Mean (also aliased as average) - Sample variance - Standard deviation * In array helper methods, use size vs length * Add KC - Keltner Channel - Add require 'kc' to technical_analysis - Create calculation - Create spec - Update array helper from Bollinger Bands * Add DC - Donchian Channel - Add require 'dc' to technical_analysis - Create calculation - Create spec * Add MACD - Moving Average Convergence Divergence - Add require 'macd' to technical_analysis - Create calculation - Create spec - Import array helper from Bollinger Bands * Refactor EMA logic into its own method * Add back obv_mean * Refactor - Add StockCalculation helper - Add true_range method to StockCalculation - Replace manual averages with Array.average helper * Add typical_price helper to StockCalculation - Update typical_price calculations to use new helper * Add ema to StockCalculation * Update calculation to use Array.average helper * Minor code format updates * Remove comments about sorting data by date * Change date to date_time --- lib/technical_analysis.rb | 38 ++++++- lib/technical_analysis/helpers/array.rb | 28 ++++- .../helpers/stock_calculation.rb | 23 ++++ lib/technical_analysis/helpers/validation.rb | 11 +- lib/technical_analysis/indicators/adi.rb | 35 ++++++ lib/technical_analysis/indicators/adtv.rb | 32 ++++++ lib/technical_analysis/indicators/adx.rb | 102 ++++++++++++++++++ lib/technical_analysis/indicators/ao.rb | 39 +++++++ lib/technical_analysis/indicators/atr.rb | 44 ++++++++ lib/technical_analysis/indicators/bb.rb | 47 ++++++++ lib/technical_analysis/indicators/cci.rb | 38 +++++++ lib/technical_analysis/indicators/cmf.rb | 39 +++++++ lib/technical_analysis/indicators/cr.rb | 27 +++++ lib/technical_analysis/indicators/dc.rb | 40 +++++++ lib/technical_analysis/indicators/dlr.rb | 32 ++++++ lib/technical_analysis/indicators/dpo.rb | 39 +++++++ lib/technical_analysis/indicators/dr.rb | 31 ++++++ lib/technical_analysis/indicators/eom.rb | 39 +++++++ lib/technical_analysis/indicators/evm.rb | 3 + lib/technical_analysis/indicators/fi.rb | 28 +++++ lib/technical_analysis/indicators/ichimoku.rb | 91 ++++++++++++++++ lib/technical_analysis/indicators/kc.rb | 48 +++++++++ lib/technical_analysis/indicators/kst.rb | 58 ++++++++++ lib/technical_analysis/indicators/macd.rb | 65 +++++++++++ lib/technical_analysis/indicators/mfi.rb | 54 ++++++++++ lib/technical_analysis/indicators/mi.rb | 55 ++++++++++ lib/technical_analysis/indicators/nvi.rb | 37 +++++++ lib/technical_analysis/indicators/obv.rb | 39 +++++++ lib/technical_analysis/indicators/obv_mean.rb | 45 ++++++++ lib/technical_analysis/indicators/rsi.rb | 67 ++++++++++++ lib/technical_analysis/indicators/sma.rb | 24 +++-- lib/technical_analysis/indicators/sr.rb | 53 +++++++++ lib/technical_analysis/indicators/trix.rb | 61 +++++++++++ lib/technical_analysis/indicators/tsi.rb | 69 ++++++++++++ lib/technical_analysis/indicators/uo.rb | 60 +++++++++++ lib/technical_analysis/indicators/vi.rb | 50 +++++++++ lib/technical_analysis/indicators/vpt.rb | 30 ++++++ lib/technical_analysis/indicators/wr.rb | 38 +++++++ spec/spec_helper.rb | 26 +++++ spec/ta_test_data.csv | 64 +++++++++++ .../technical_analysis/indicators/adi_spec.rb | 83 ++++++++++++++ .../indicators/adtv_spec.rb | 65 +++++++++++ .../technical_analysis/indicators/adx_spec.rb | 59 ++++++++++ spec/technical_analysis/indicators/ao_spec.rb | 53 +++++++++ .../technical_analysis/indicators/atr_spec.rb | 72 +++++++++++++ spec/technical_analysis/indicators/bb_spec.rb | 67 ++++++++++++ .../technical_analysis/indicators/cci_spec.rb | 67 ++++++++++++ .../technical_analysis/indicators/cmf_spec.rb | 67 ++++++++++++ spec/technical_analysis/indicators/cr_spec.rb | 86 +++++++++++++++ spec/technical_analysis/indicators/dc_spec.rb | 67 ++++++++++++ .../technical_analysis/indicators/dlr_spec.rb | 86 +++++++++++++++ .../technical_analysis/indicators/dpo_spec.rb | 57 ++++++++++ spec/technical_analysis/indicators/dr_spec.rb | 86 +++++++++++++++ .../technical_analysis/indicators/eom_spec.rb | 72 +++++++++++++ .../technical_analysis/indicators/evm_spec.rb | 72 +++++++++++++ spec/technical_analysis/indicators/fi_spec.rb | 85 +++++++++++++++ .../indicators/ichimoku_spec.rb | 62 +++++++++++ spec/technical_analysis/indicators/kc_spec.rb | 77 +++++++++++++ .../technical_analysis/indicators/kst_spec.rb | 45 ++++++++ .../indicators/macd_spec.rb | 53 +++++++++ .../technical_analysis/indicators/mfi_spec.rb | 72 +++++++++++++ spec/technical_analysis/indicators/mi_spec.rb | 46 ++++++++ .../technical_analysis/indicators/nvi_spec.rb | 86 +++++++++++++++ .../indicators/obv_mean_spec.rb | 76 +++++++++++++ .../technical_analysis/indicators/obv_spec.rb | 86 +++++++++++++++ .../technical_analysis/indicators/rsi_spec.rb | 72 +++++++++++++ .../technical_analysis/indicators/sma_spec.rb | 98 +++++++++++------ spec/technical_analysis/indicators/sr_spec.rb | 71 ++++++++++++ .../indicators/trix_spec.rb | 43 ++++++++ .../technical_analysis/indicators/tsi_spec.rb | 54 ++++++++++ spec/technical_analysis/indicators/uo_spec.rb | 58 ++++++++++ spec/technical_analysis/indicators/vi_spec.rb | 72 +++++++++++++ .../technical_analysis/indicators/vpt_spec.rb | 85 +++++++++++++++ spec/technical_analysis/indicators/wr_spec.rb | 73 +++++++++++++ 74 files changed, 4071 insertions(+), 51 deletions(-) create mode 100644 lib/technical_analysis/helpers/stock_calculation.rb create mode 100644 lib/technical_analysis/indicators/adi.rb create mode 100644 lib/technical_analysis/indicators/adtv.rb create mode 100644 lib/technical_analysis/indicators/adx.rb create mode 100644 lib/technical_analysis/indicators/ao.rb create mode 100644 lib/technical_analysis/indicators/atr.rb create mode 100644 lib/technical_analysis/indicators/bb.rb create mode 100644 lib/technical_analysis/indicators/cci.rb create mode 100644 lib/technical_analysis/indicators/cmf.rb create mode 100644 lib/technical_analysis/indicators/cr.rb create mode 100644 lib/technical_analysis/indicators/dc.rb create mode 100644 lib/technical_analysis/indicators/dlr.rb create mode 100644 lib/technical_analysis/indicators/dpo.rb create mode 100644 lib/technical_analysis/indicators/dr.rb create mode 100644 lib/technical_analysis/indicators/eom.rb create mode 100644 lib/technical_analysis/indicators/evm.rb create mode 100644 lib/technical_analysis/indicators/fi.rb create mode 100644 lib/technical_analysis/indicators/ichimoku.rb create mode 100644 lib/technical_analysis/indicators/kc.rb create mode 100644 lib/technical_analysis/indicators/kst.rb create mode 100644 lib/technical_analysis/indicators/macd.rb create mode 100644 lib/technical_analysis/indicators/mfi.rb create mode 100644 lib/technical_analysis/indicators/mi.rb create mode 100644 lib/technical_analysis/indicators/nvi.rb create mode 100644 lib/technical_analysis/indicators/obv.rb create mode 100644 lib/technical_analysis/indicators/obv_mean.rb create mode 100644 lib/technical_analysis/indicators/rsi.rb create mode 100644 lib/technical_analysis/indicators/sr.rb create mode 100644 lib/technical_analysis/indicators/trix.rb create mode 100644 lib/technical_analysis/indicators/tsi.rb create mode 100644 lib/technical_analysis/indicators/uo.rb create mode 100644 lib/technical_analysis/indicators/vi.rb create mode 100644 lib/technical_analysis/indicators/vpt.rb create mode 100644 lib/technical_analysis/indicators/wr.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/ta_test_data.csv create mode 100644 spec/technical_analysis/indicators/adi_spec.rb create mode 100644 spec/technical_analysis/indicators/adtv_spec.rb create mode 100644 spec/technical_analysis/indicators/adx_spec.rb create mode 100644 spec/technical_analysis/indicators/ao_spec.rb create mode 100644 spec/technical_analysis/indicators/atr_spec.rb create mode 100644 spec/technical_analysis/indicators/bb_spec.rb create mode 100644 spec/technical_analysis/indicators/cci_spec.rb create mode 100644 spec/technical_analysis/indicators/cmf_spec.rb create mode 100644 spec/technical_analysis/indicators/cr_spec.rb create mode 100644 spec/technical_analysis/indicators/dc_spec.rb create mode 100644 spec/technical_analysis/indicators/dlr_spec.rb create mode 100644 spec/technical_analysis/indicators/dpo_spec.rb create mode 100644 spec/technical_analysis/indicators/dr_spec.rb create mode 100644 spec/technical_analysis/indicators/eom_spec.rb create mode 100644 spec/technical_analysis/indicators/evm_spec.rb create mode 100644 spec/technical_analysis/indicators/fi_spec.rb create mode 100644 spec/technical_analysis/indicators/ichimoku_spec.rb create mode 100644 spec/technical_analysis/indicators/kc_spec.rb create mode 100644 spec/technical_analysis/indicators/kst_spec.rb create mode 100644 spec/technical_analysis/indicators/macd_spec.rb create mode 100644 spec/technical_analysis/indicators/mfi_spec.rb create mode 100644 spec/technical_analysis/indicators/mi_spec.rb create mode 100644 spec/technical_analysis/indicators/nvi_spec.rb create mode 100644 spec/technical_analysis/indicators/obv_mean_spec.rb create mode 100644 spec/technical_analysis/indicators/obv_spec.rb create mode 100644 spec/technical_analysis/indicators/rsi_spec.rb create mode 100644 spec/technical_analysis/indicators/sr_spec.rb create mode 100644 spec/technical_analysis/indicators/trix_spec.rb create mode 100644 spec/technical_analysis/indicators/tsi_spec.rb create mode 100644 spec/technical_analysis/indicators/uo_spec.rb create mode 100644 spec/technical_analysis/indicators/vi_spec.rb create mode 100644 spec/technical_analysis/indicators/vpt_spec.rb create mode 100644 spec/technical_analysis/indicators/wr_spec.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index fed0241..15274cf 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -1,8 +1,40 @@ -require "technical_analysis/calculate" - # Helpers require 'technical_analysis/helpers/array' +require 'technical_analysis/helpers/stock_calculation' require 'technical_analysis/helpers/validation' # Indicators -require 'technical_analysis/indicators/sma' \ No newline at end of file +require 'technical_analysis/indicators/adi' +require 'technical_analysis/indicators/adtv' +require 'technical_analysis/indicators/adx' +require 'technical_analysis/indicators/ao' +require 'technical_analysis/indicators/atr' +require 'technical_analysis/indicators/bb' +require 'technical_analysis/indicators/cci' +require 'technical_analysis/indicators/cmf' +require 'technical_analysis/indicators/cr' +require 'technical_analysis/indicators/dc' +require 'technical_analysis/indicators/dlr' +require 'technical_analysis/indicators/dpo' +require 'technical_analysis/indicators/dr' +require 'technical_analysis/indicators/eom' +require 'technical_analysis/indicators/evm' +require 'technical_analysis/indicators/fi' +require 'technical_analysis/indicators/ichimoku' +require 'technical_analysis/indicators/kc' +require 'technical_analysis/indicators/kst' +require 'technical_analysis/indicators/macd' +require 'technical_analysis/indicators/mfi' +require 'technical_analysis/indicators/mi' +require 'technical_analysis/indicators/nvi' +require 'technical_analysis/indicators/obv' +require 'technical_analysis/indicators/obv_mean' +require 'technical_analysis/indicators/rsi' +require 'technical_analysis/indicators/sma' +require 'technical_analysis/indicators/sr' +require 'technical_analysis/indicators/trix' +require 'technical_analysis/indicators/tsi' +require 'technical_analysis/indicators/uo' +require 'technical_analysis/indicators/vi' +require 'technical_analysis/indicators/vpt' +require 'technical_analysis/indicators/wr' diff --git a/lib/technical_analysis/helpers/array.rb b/lib/technical_analysis/helpers/array.rb index 8d60578..ef33391 100644 --- a/lib/technical_analysis/helpers/array.rb +++ b/lib/technical_analysis/helpers/array.rb @@ -1,5 +1,31 @@ class Array + def sum self.inject(0, :+) end -end \ No newline at end of file + + def mean + self.sum / self.size.to_f + end + + def sample_variance + m = self.mean + sum = self.inject(0) { |accum, i| accum + (i - m)**2 } + sum / (self.size - 1).to_f + end + + def standard_deviation + Math.sqrt(self.sample_variance) + end + + def sort_by_hash_date_time_asc + self.sort_by { |row| row[:date_time] } + end + + def sort_by_hash_date_time_desc + sort_by_hash_date_time_asc.reverse + end + + alias_method :average, :mean + +end diff --git a/lib/technical_analysis/helpers/stock_calculation.rb b/lib/technical_analysis/helpers/stock_calculation.rb new file mode 100644 index 0000000..6bd6d26 --- /dev/null +++ b/lib/technical_analysis/helpers/stock_calculation.rb @@ -0,0 +1,23 @@ +class StockCalculation + + def self.true_range(current_high, current_low, previous_close) + [ + (current_high - current_low), + (current_high - previous_close).abs, + (current_low - previous_close).abs + ].max + end + + def self.typical_price(price) + (price[:high] + price[:low] + price[:close]) / 3.0 + end + + def self.ema(current_value, data, period, prev_value) + if prev_value.nil? + data.average + else + (current_value - prev_value) * (2.0 / (period + 1.0)) + prev_value + end + end + +end diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 339fe2b..6366577 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -1,8 +1,10 @@ class Validation - def self.validate_price_data(data) - unless data.values.all? { |v| v.class == Float || v.class == Integer} - raise ValidationError.new "Invalid Data. Price is not a number" + def self.validate_numeric_data(data, *keys) + keys.each do |key| + unless data.all? { |v| v[key].is_a? Numeric } + raise ValidationError.new "Invalid Data. '#{key}' is not valid price data." + end end end @@ -11,4 +13,5 @@ def self.validate_length(data, size) end class ValidationError < StandardError; end -end \ No newline at end of file + +end diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb new file mode 100644 index 0000000..ddf76aa --- /dev/null +++ b/lib/technical_analysis/indicators/adi.rb @@ -0,0 +1,35 @@ +module TechnicalAnalysis + class Adi + + # Calculates the Accumulation/Distribution Index for the given data + # https://en.wikipedia.org/wiki/Accumulation/distribution_index + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data) + Validation.validate_numeric_data(data, :high, :low, :close, :volume) + + data = data.sort_by_hash_date_time_asc + + ad = 0 + ads = [] + clv = 0 + prev_ad = 0 + + data.each_with_index do |values, i| + if values[:high] == values[:low] + clv = 0 + else + clv = ((values[:close] - values[:low]) - (values[:high] - values[:close])) / (values[:high] - values[:low]) + end + + ad = prev_ad + (clv * values[:volume]) + prev_ad = ad + + ads << { date_time: values[:date_time], value: ad } + end + ads + end + + end +end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb new file mode 100644 index 0000000..c616477 --- /dev/null +++ b/lib/technical_analysis/indicators/adtv.rb @@ -0,0 +1,32 @@ +module TechnicalAnalysis + class Adtv + + # Calculates the average daily trading volume (ADTV) for the data over the given period + # https://www.investopedia.com/terms/a/averagedailytradingvolume.asp + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given number of days used to calculate the ADTV + # @param volume_key [Symbol] The hash key for the volume data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 22, volume_key: :value) + Validation.validate_numeric_data(data, volume_key) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + period_values << v[volume_key] + if period_values.size == period + output << { date_time: v[:date_time], value: period_values.average } + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb new file mode 100644 index 0000000..b36ae45 --- /dev/null +++ b/lib/technical_analysis/indicators/adx.rb @@ -0,0 +1,102 @@ +module TechnicalAnalysis + class Adx + + # Calculates the average directional index (ADX) for the data over the given period + # https://en.wikipedia.org/wiki/Average_directional_movement_index + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the ADX + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period * 2) + + data = data.sort_by_hash_date_time_asc + + dx_values = [] + output = [] + periodic_values = [] + prev_adx = nil + prev_price = data.shift + smoothed_values = [] + + data.each do |v| + tr = StockCalculation.true_range(v[:high], v[:low], prev_price[:close]) + + dm_pos, dm_neg = calculate_dm(v, prev_price) + + periodic_values << { tr: tr, dm_pos: dm_pos, dm_neg: dm_neg } + + if periodic_values.size == period + tr_period, dm_pos_period, dm_neg_period = smooth_periodic_values(period, periodic_values, smoothed_values) + smoothed_values << { tr: tr_period, dm_pos: dm_pos_period, dm_neg: dm_neg_period } + + di_pos = (dm_pos_period / tr_period) * 100.00 + di_neg = (dm_neg_period / tr_period) * 100.00 + dx = ((dm_pos_period - dm_neg_period).abs / (dm_pos_period + dm_neg_period) * 100.00) + + dx_values << dx + + if dx_values.size == period + if prev_adx.nil? + adx = dx_values.average + else + adx = ((prev_adx * 13) + dx) / period.to_f + end + + output << { + date_time: v[:date_time], + value: { + adx: adx, + di_pos: di_pos, + di_neg: di_neg + } + } + + prev_adx = adx + dx_values.shift + end + + periodic_values.shift + end + + prev_price = v + end + + output + end + + def self.calculate_dm(current_price, prev_price) + if current_price[:high] - prev_price[:high] > prev_price[:low] - current_price[:low] + dm_pos = [(current_price[:high] - prev_price[:high]), 0].max + dm_neg = 0 + elsif prev_price[:low] - current_price[:low] > current_price[:high] - prev_price[:high] + dm_pos = 0 + dm_neg = [(prev_price[:low] - current_price[:low]), 0].max + else + dm_pos = 0 + dm_neg = 0 + end + + [dm_pos, dm_neg] + end + + def self.smooth_periodic_values(period, periodic_values, smoothed_values) + if smoothed_values.empty? + tr_period = periodic_values.map { |pv| pv[:tr] }.sum + dm_pos_period = periodic_values.map { |pv| pv[:dm_pos] }.sum + dm_neg_period = periodic_values.map { |pv| pv[:dm_neg] }.sum + else + prev_value = smoothed_values.last + current_value = periodic_values.last + + tr_period = prev_value[:tr] - (prev_value[:tr] / period) + current_value[:tr] + dm_pos_period = prev_value[:dm_pos] - (prev_value[:dm_pos] / period) + current_value[:dm_pos] + dm_neg_period = prev_value[:dm_neg] - (prev_value[:dm_neg] / period) + current_value[:dm_neg] + end + + [tr_period, dm_pos_period, dm_neg_period] + end + + end +end diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb new file mode 100644 index 0000000..1ae788a --- /dev/null +++ b/lib/technical_analysis/indicators/ao.rb @@ -0,0 +1,39 @@ +module TechnicalAnalysis + class Ao + + # Calculates the Awesome Oscillator for the data over the given period + # https://www.tradingview.com/wiki/Awesome_Oscillator_(AO) + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low) + # @param short_period [Integer] The given period to calculate the short period SMA + # @param long_period [Integer] The given period to calculate the long period SMA + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, short_period: 5, long_period: 34) + Validation.validate_numeric_data(data, :high, :low) + Validation.validate_length(data, long_period) + + data = data.sort_by_hash_date_time_asc + + midpoint_values = [] + output = [] + + data.each do |v| + midpoint = (v[:high] + v[:low]) / 2 + midpoint_values << midpoint + + if midpoint_values.size == long_period + short_period_sma = midpoint_values.last(short_period).average + long_period_sma = midpoint_values.average + value = short_period_sma - long_period_sma + + output << { date_time: v[:date_time], value: value } + + midpoint_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb new file mode 100644 index 0000000..bfe5e5b --- /dev/null +++ b/lib/technical_analysis/indicators/atr.rb @@ -0,0 +1,44 @@ +module TechnicalAnalysis + class Atr + + # Calculates the average true range (ATR) for the data over the given period + # https://en.wikipedia.org/wiki/Average_true_range + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given period to calculate the ATR + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period + 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + prev_price = data.shift + + data.each do |v| + tr = StockCalculation.true_range(v[:high], v[:low], prev_price[:close]) + + period_values << tr + + if period_values.size == period + if output.empty? + atr = period_values.average + else + atr = (output.last[:value] * (period - 1.0) + tr) / period.to_f + end + + output << { date_time: v[:date_time], value: atr } + + period_values.shift + end + + prev_price = v + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb new file mode 100644 index 0000000..ef11306 --- /dev/null +++ b/lib/technical_analysis/indicators/bb.rb @@ -0,0 +1,47 @@ +module TechnicalAnalysis + class Bb + + # Calculates the bollinger bands (BB) for the data over the given period + # https://en.wikipedia.org/wiki/Bollinger_Bands + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the BB + # @param standard_deviations [Integer] The given standard deviations to calculate the upper and lower bands of the BB + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + period_values << v[price_key] + + if period_values.size == period + mb = period_values.average + sd = period_values.standard_deviation + ub = mb + standard_deviations * sd + lb = mb - standard_deviations * sd + + output << { + date_time: v[:date_time], + value: { + middle_band: mb, + upper_band: ub, + lower_band: lb + } + } + + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb new file mode 100644 index 0000000..066dde2 --- /dev/null +++ b/lib/technical_analysis/indicators/cci.rb @@ -0,0 +1,38 @@ +module TechnicalAnalysis + class Cci + + # Calculates the commodity channel index for the data over the given period + # https://en.wikipedia.org/wiki/Commodity_channel_index + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given period to calculate the CCI + # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of CCI values would fall between −100 and +100 + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 20, constant: 0.015) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + typical_prices = [] + + data.each do |v| + typical_price = StockCalculation.typical_price(v) + typical_prices << typical_price + + if typical_prices.size == period + period_sma = typical_prices.average + mean_deviation = typical_prices.map { |tp| (tp - period_sma).abs }.mean + cci = (typical_price - period_sma) / (constant * mean_deviation) + + output << { date_time: v[:date_time], value: cci } + typical_prices.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb new file mode 100644 index 0000000..b660036 --- /dev/null +++ b/lib/technical_analysis/indicators/cmf.rb @@ -0,0 +1,39 @@ +module TechnicalAnalysis + class Cmf + + # Calculates the chaikin money flow (CMF) for the data over the given period + # https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:chaikin_money_flow_cmf + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) + # @param period [Integer] The given period to calculate the CMF + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 20) + Validation.validate_numeric_data(data, :high, :low, :close, :volume) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + multiplier = ((v[:close] - v[:low]) - (v[:high] - v[:close])) / (v[:high] - v[:low]) + mf_volume = multiplier * v[:volume] + + period_values << { volume: v[:volume], mf_volume: mf_volume } + + if period_values.size == period + volume_sum = period_values.map { |pv| pv[:volume] }.sum + mf_volume_sum = period_values.map { |pv| pv[:mf_volume] }.sum + cmf = mf_volume_sum / volume_sum + + output << { date_time: v[:date_time], value: cmf } + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb new file mode 100644 index 0000000..3f504ab --- /dev/null +++ b/lib/technical_analysis/indicators/cr.rb @@ -0,0 +1,27 @@ +module TechnicalAnalysis + class Cr + + # Calculates the cumulative return for the data over the given period + # https://www.investopedia.com/terms/c/cumulativereturn.asp + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + start_price = data.first[price_key] + + data.each do |v| + output << { date_time: v[:date_time], value: ((v[price_key] - start_price) / start_price) } + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb new file mode 100644 index 0000000..da83e44 --- /dev/null +++ b/lib/technical_analysis/indicators/dc.rb @@ -0,0 +1,40 @@ +module TechnicalAnalysis + class Dc + + # Calculates the donchian channel (DC) for the data over the given period + # https://en.wikipedia.org/wiki/Donchian_channel + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the DC + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 20, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + period_values << v[price_key] + + if period_values.size == period + output << { + date_time: v[:date_time], + value: { + upper_bound: period_values.max, + lower_bound: period_values.min + } + } + + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb new file mode 100644 index 0000000..c1f0d54 --- /dev/null +++ b/lib/technical_analysis/indicators/dlr.rb @@ -0,0 +1,32 @@ +module TechnicalAnalysis + class Dlr + + # Calculates the daily log return (percent expressed as a decimal) for the data over the given period + # https://www.quora.com/What-are-daily-log-returns-of-an-equity + # https://en.wikipedia.org/wiki/Rate_of_return#Logarithmic_or_continuously_compounded_return + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + prev_price = data.first[price_key].to_f + + data.each do |v| + current_price = v[:close].to_f + + output << { date_time: v[:date_time], value: Math.log(current_price / prev_price) } + + prev_price = current_price + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb new file mode 100644 index 0000000..71b65d2 --- /dev/null +++ b/lib/technical_analysis/indicators/dpo.rb @@ -0,0 +1,39 @@ +module TechnicalAnalysis + class Dpo + + # Calculates the detrended price oscillator for the data over the given period + # https://en.wikipedia.org/wiki/Detrended_price_oscillator + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the SMA + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 20, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, period + (period / 2)) + + data = data.sort_by_hash_date_time_asc + + 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 = data[sma_range].map { |v| v[price_key] }.average + + dop = (current_price - midpoint_period_sma) + + output << { date_time: date_time, value: dop } + index += 1 + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb new file mode 100644 index 0000000..f192057 --- /dev/null +++ b/lib/technical_analysis/indicators/dr.rb @@ -0,0 +1,31 @@ +module TechnicalAnalysis + class Dr + + # Calculates the daily return (percent expressed as a decimal) for the data over the given period + # https://en.wikipedia.org/wiki/Rate_of_return + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + prev_price = data.first[price_key].to_f + + data.each do |v| + current_price = v[:close].to_f + + output << { date_time: v[:date_time], value: ((current_price / prev_price) - 1) } + + prev_price = current_price + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb new file mode 100644 index 0000000..c2719e9 --- /dev/null +++ b/lib/technical_analysis/indicators/eom.rb @@ -0,0 +1,39 @@ +module TechnicalAnalysis + class Eom + + # Calculates the ease of movement (EoM and EVM) for the data over the given period + # https://en.wikipedia.org/wiki/Ease_of_movement + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) + # @param period [Integer] The given period to calculate the Eom / EVM + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :volume) + Validation.validate_length(data, period + 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + prev_price = data.shift + + data.each do |v| + distance_moved = ((v[:high] + v[:low]) / 2) - ((prev_price[:high] + prev_price[:low]) / 2) + box_ratio = (v[:volume] / 100_000_000.00) / (v[:high] - v[:low]) + emv = distance_moved / box_ratio + + period_values << emv + + if period_values.size == period + output << { date_time: v[:date_time], value: period_values.average } + period_values.shift + end + + prev_price = v + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb new file mode 100644 index 0000000..ef46092 --- /dev/null +++ b/lib/technical_analysis/indicators/evm.rb @@ -0,0 +1,3 @@ +module TechnicalAnalysis + Evm = Eom +end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb new file mode 100644 index 0000000..3d656f2 --- /dev/null +++ b/lib/technical_analysis/indicators/fi.rb @@ -0,0 +1,28 @@ +module TechnicalAnalysis + class Fi + + # Calculates the force index (FI) for the data + # https://en.wikipedia.org/wiki/Force_index + # + # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data) + Validation.validate_numeric_data(data, :close, :volume) + Validation.validate_length(data, 2) + + data = data.sort_by_hash_date_time_asc + + output = [] + prev_price = data.shift + + data.each do |v| + fi = ((v[:close] - prev_price[:close]) * v[:volume]) + output << { date_time: v[:date_time], value: fi } + prev_price = v + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb new file mode 100644 index 0000000..a4788b5 --- /dev/null +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -0,0 +1,91 @@ +module TechnicalAnalysis + class Ichimoku + + # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimooku) for the data over the given period + # 1. tenkan_sen (Conversion Line) + # 2. kijun_sen (Base Line) + # 3. senkou_span_a (Leading Span A) + # 4. senkou_span_b (Leading Span B) + # 5. chickou_span (Lagging Span) + # https://en.wikipedia.org/wiki/Ichimoku_Kink%C5%8D_Hy%C5%8D + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param low_period [Integer] The given period to calculate tenkan_sen (Conversion Line) + # @param medium_period [Integer] The given period to calculate kijun_sen (Base Line), senkou_span_a (Leading Span A), and chikou_span (Lagging Span) + # @param high_period [Integer] The given period to calculate senkou_span_b (Leadning Span B) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, high_period + medium_period - 2) + + data = data.sort_by_hash_date_time_asc + + index = high_period + medium_period - 2 + output = [] + + while index < data.size + date_time = data[index][:date_time] + + tenkan_sen = calculate_midpoint(index, low_period, data) + kinjun_sen = calculate_midpoint(index, medium_period, data) + senkou_span_a = calculate_senkou_span_a(index, low_period, medium_period, data) + senkou_span_b = calculate_senkou_span_b(index, medium_period, high_period, data) + chikou_span = calculate_chikou_span(index, medium_period, data) + + output << { + date_time: date_time, + value: { + tenkan_sen: tenkan_sen, + kijun_sen: kinjun_sen, + senkou_span_a: senkou_span_a, + senkou_span_b: senkou_span_b, + chikou_span: chikou_span + } + } + + index += 1 + end + + output + end + + def self.lowest_low(prices) + prices.map { |price| price[:low] }.min + end + + def self.highest_high(prices) + prices.map { |price| price[:high] }.max + end + + def self.calculate_midpoint(index, period, data) + period_range = ((index - (period - 1))..index) + period_data = data[period_range] + lowest_low = lowest_low(period_data) + highest_high = highest_high(period_data) + + ((highest_high + lowest_low) / 2.0) + end + + def self.calculate_senkou_span_a(index, low_period, medium_period, data) + mp_ago_index = (index - (medium_period - 1)) + + tenkan_sen_mp_ago = calculate_midpoint(mp_ago_index, low_period, data) + kinjun_sen_mp_ago = calculate_midpoint(mp_ago_index, medium_period, data) + + ((tenkan_sen_mp_ago + kinjun_sen_mp_ago) / 2.0) + end + + def self.calculate_senkou_span_b(index, medium_period, high_period, data) + mp_ago_index = (index - (medium_period - 1)) + + calculate_midpoint(mp_ago_index, high_period, data) + end + + def self.calculate_chikou_span(index, medium_period, data) + mp_ago_index = (index - (medium_period - 1)) + + data[mp_ago_index][:close] + end + + end +end diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb new file mode 100644 index 0000000..242f0fe --- /dev/null +++ b/lib/technical_analysis/indicators/kc.rb @@ -0,0 +1,48 @@ +module TechnicalAnalysis + class Kc + + # Calculates the keltner channel (KC) for the data over the given period + # https://en.wikipedia.org/wiki/Keltner_channel + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given period to calculate the KC + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 10) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + tp = StockCalculation.typical_price(v) + tr = v[:high] - v[:low] + period_values << { typical_price: tp, trading_range: tr } + + if period_values.size == period + mb = period_values.map { |pv| pv[:typical_price] }.average + + trading_range_average = period_values.map { |pv| pv[:trading_range] }.average + ub = mb + trading_range_average + lb = mb - trading_range_average + + output << { + date_time: v[:date_time], + value: { + middle_band: mb, + upper_band: ub, + lower_band: lb + } + } + + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb new file mode 100644 index 0000000..2b2180b --- /dev/null +++ b/lib/technical_analysis/indicators/kst.rb @@ -0,0 +1,58 @@ +module TechnicalAnalysis + class Kst + + # Calculates the know sure thing for the data over the given period + # https://en.wikipedia.org/wiki/KST_oscillator + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param roc1 [Integer] The given period to calculate the rate-of-change for RCMA1 + # @param roc2 [Integer] The given period to calculate the rate-of-change for RCMA2 + # @param roc3 [Integer] The given period to calculate the rate-of-change for RCMA3 + # @param roc4 [Integer] The given period to calculate the rate-of-change for RCMA4 + # @param sma1 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA1 + # @param sma2 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA2 + # @param sma3 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA3 + # @param sma4 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA4 + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, roc4 + sma4 - 1) + + data = data.sort_by_hash_date_time_asc + + index = roc4 + sma4 - 2 + output = [] + + while index < data.size + date_time = data[index][:date_time] + rcma1 = calculate_rcma(data, index, price_key, roc1, sma1) + rcma2 = calculate_rcma(data, index, price_key, roc2, sma2) + rcma3 = calculate_rcma(data, index, price_key, roc3, sma3) + rcma4 = calculate_rcma(data, index, price_key, roc4, sma4) + + kst = (1 * rcma1) + (2 * rcma2) + (3 * rcma3) + (4 * rcma4) + + output << { date_time: date_time, value: kst } + index += 1 + end + + output + end + + def self.calculate_rcma(data, index, price_key, roc, sma) + roc_data = [] + index_range = (index - sma + 1)..index + + index_range.each do |i| + last_price = data[i][price_key] + starting_price = data[i - roc + 1][price_key] + + roc_data << (last_price - starting_price) / starting_price * 100 + end + + roc_data.sum / sma.to_f + end + + end +end diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb new file mode 100644 index 0000000..a7d5afc --- /dev/null +++ b/lib/technical_analysis/indicators/macd.rb @@ -0,0 +1,65 @@ +module TechnicalAnalysis + class Macd + + # Calculates the moving average convergence divergence (MACD) for the data over the given period + # https://en.wikipedia.org/wiki/MACD + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param fast_period [Integer] The given period to calculate the fast moving EMA for MACD + # @param slow_period [Integer] The given period to calculate the slow moving EMA for MACD + # @param signal_period [Integer] The given period to calculate the singal line for MACD + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, slow_period + signal_period) + + data = data.sort_by_hash_date_time_asc + + macd_values = [] + output = [] + period_values = [] + prev_fast_ema = nil + prev_signal = nil + prev_slow_ema = nil + + data.each do |v| + period_values << v[price_key] + + if period_values.size >= fast_period + fast_ema = StockCalculation.ema(v[price_key], period_values, fast_period, prev_fast_ema) + prev_fast_ema = fast_ema + + if period_values.size == slow_period + slow_ema = StockCalculation.ema(v[price_key], period_values, slow_period, prev_slow_ema) + prev_slow_ema = slow_ema + + macd = fast_ema - slow_ema + macd_values << macd + + if macd_values.size == signal_period + signal = StockCalculation.ema(macd, macd_values, signal_period, prev_signal) + prev_signal = signal + + output << { + date_time: v[:date_time], + value: { + macd_line: macd, + signal_line: signal, + macd_histogram: macd - signal, + } + } + + macd_values.shift + end + + period_values.shift + end + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb new file mode 100644 index 0000000..3743291 --- /dev/null +++ b/lib/technical_analysis/indicators/mfi.rb @@ -0,0 +1,54 @@ +module TechnicalAnalysis + class Mfi + + # Calculates the money flow index (MFI) for the data over the given period + # https://en.wikipedia.org/wiki/Money_flow_index + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) + # @param period [Integer] The given period to calculate the MFI + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :close, :volume) + Validation.validate_length(data, period + 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + prev_typical_price = StockCalculation.typical_price(data.first) + raw_money_flows = [] + + data.shift + + data.each do |v| + typical_price = StockCalculation.typical_price(v) + + if typical_price < prev_typical_price + money_flow = (-1.0 * typical_price * v[:volume]) + elsif typical_price > prev_typical_price + money_flow = (typical_price * v[:volume]) + else + money_flow = 0.0 + end + + raw_money_flows << money_flow + + if raw_money_flows.size == period + positive_period_flows = raw_money_flows.map { |rmf| rmf.positive? ? rmf : 0 }.sum + negative_period_flows = raw_money_flows.map { |rmf| rmf.negative? ? rmf.abs : 0 }.sum + + money_flow_ratio = (positive_period_flows / negative_period_flows) + mfi = (100.00 - (100.00 / (1.0 + money_flow_ratio))) + + output << { date_time: v[:date_time], value: mfi } + + raw_money_flows.shift + end + + prev_typical_price = typical_price + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb new file mode 100644 index 0000000..ba7872a --- /dev/null +++ b/lib/technical_analysis/indicators/mi.rb @@ -0,0 +1,55 @@ +module TechnicalAnalysis + class Mi + + # Calculates the mass index (MI) for the data over the given period + # https://en.wikipedia.org/wiki/Mass_index + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low) + # @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA + # @param period [Integer] The given period to calculate the MI + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, ema_period: 9, sum_period: 25) + Validation.validate_numeric_data(data, :high, :low) + Validation.validate_length(data, (ema_period * 2) + sum_period - 2) + + data = data.sort_by_hash_date_time_asc + + double_emas = [] + high_low_diffs = [] + output = [] + ratio_of_emas = [] + single_emas = [] + + data.each do |v| + high_low_diff = v[:high] - v[:low] + high_low_diffs << high_low_diff + + if high_low_diffs.size == ema_period + single_ema = StockCalculation.ema(high_low_diff, high_low_diffs, ema_period, single_emas.last) + single_emas << single_ema + + if single_emas.size == ema_period + double_ema = StockCalculation.ema(single_emas.last, single_emas, ema_period, double_emas.last) + double_emas << double_ema + + ratio_of_emas << (single_ema / double_ema) + + if ratio_of_emas.size == sum_period + output << { date_time: v[:date_time], value: ratio_of_emas.sum } + + double_emas.shift + ratio_of_emas.shift + end + + single_emas.shift + end + + high_low_diffs.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb new file mode 100644 index 0000000..1fd4c43 --- /dev/null +++ b/lib/technical_analysis/indicators/nvi.rb @@ -0,0 +1,37 @@ +module TechnicalAnalysis + class Nvi + + # Calculates the negative volume index (NVI) for the data + # https://en.wikipedia.org/wiki/Negative_volume_index + # + # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data) + Validation.validate_numeric_data(data, :close, :volume) + Validation.validate_length(data, 1) + + data = data.sort_by_hash_date_time_asc + + nvi_cumulative = 1_000.00 + output = [] + prev_price = data.shift + + output << { date_time: prev_price[:date_time], value: nvi_cumulative } # Start with default of 1_000 + + data.each do |v| + volume_change = ((v[:volume] - prev_price[:volume]) / prev_price[:volume]) + + if volume_change < 0 + price_change = ((v[:close] - prev_price[:close]) / prev_price[:close]) * 100.00 + nvi_cumulative += price_change + end + + output << { date_time: v[:date_time], value: nvi_cumulative } + prev_price = v + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb new file mode 100644 index 0000000..c516073 --- /dev/null +++ b/lib/technical_analysis/indicators/obv.rb @@ -0,0 +1,39 @@ +module TechnicalAnalysis + class Obv + + # Calculates the on-balance volume (OBV) for the data over the given period + # https://en.wikipedia.org/wiki/On-balance_volume + # + # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data) + Validation.validate_numeric_data(data, :close, :volume) + Validation.validate_length(data, 1) + + data = data.sort_by_hash_date_time_asc + + current_obv = 0 + output = [] + prior_close = nil + prior_volume = nil + + data.each do |v| + volume = v[:volume] + close = v[:close] + + unless prior_close.nil? + current_obv += volume if close > prior_close + current_obv -= volume if close < prior_close + end + + output << { date_time: v[:date_time], value: current_obv } + + prior_volume = volume + prior_close = close + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb new file mode 100644 index 0000000..910b56e --- /dev/null +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -0,0 +1,45 @@ +module TechnicalAnalysis + class ObvMean + + # Calculates the on-balance volume mean (OBV mean) for the data over the given period + # https://en.wikipedia.org/wiki/On-balance_volume + # + # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) + # @param period [Integer] The given period to calculate the OBV mean + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 10) + Validation.validate_numeric_data(data, :close, :volume) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + current_obv = 0 + obvs = [] + output = [] + prior_close = nil + prior_volume = nil + + data.each do |v| + volume = v[:volume] + close = v[:close] + + unless prior_close.nil? + current_obv += volume if close > prior_close + current_obv -= volume if close < prior_close + obvs << current_obv + end + + prior_volume = volume + prior_close = close + + if obvs.size == period + output << { date_time: v[:date_time], value: obvs.average } + obvs.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb new file mode 100644 index 0000000..2c72a53 --- /dev/null +++ b/lib/technical_analysis/indicators/rsi.rb @@ -0,0 +1,67 @@ +module TechnicalAnalysis + class Rsi + + # Calculates the relative strength index for the data over the given period + # https://en.wikipedia.org/wiki/Relative_strength_index + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the RSI + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, period + 1) + + data = data.sort_by_hash_date_time_asc + + 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 = price_changes.map { |pc| pc.positive? ? pc : 0 }.average + avg_loss = price_changes.map { |pc| pc.negative? ? pc.abs : 0 }.average + 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 << { date_time: v[:date_time], value: rsi } + + prev_avg = { gain: avg_gain, loss: avg_loss } + price_changes.shift + end + + prev_price = v[price_key] + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 813ee96..a79f827 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -1,28 +1,32 @@ module TechnicalAnalysis class Sma + # Calculates the simple moving average for the data over the given period # https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average # - # @param data [Hash] Date strings to price values + # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA - # @return [Hash] A hash of date strings to SMA values - def self.calculate(data, period: 30) - Validation.validate_price_data(data) + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 30, price_key: :value) + Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) - output = {} - period_values = [] - data = data.sort.to_h # Sort data by descending dates + data = data.sort_by_hash_date_time_asc - data.each do |date, price| - period_values << price + output = [] + period_values = [] + + data.each do |v| + period_values << v[price_key] if period_values.size == period - output[date] = period_values.sum / period.to_f + output << { date_time: v[:date_time], value: period_values.average } period_values.shift end end output end + end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb new file mode 100644 index 0000000..798cc3b --- /dev/null +++ b/lib/technical_analysis/indicators/sr.rb @@ -0,0 +1,53 @@ +module TechnicalAnalysis + class Sr + + # Calculates the stochastic oscillator (%K) for the data over the given period + # https://en.wikipedia.org/wiki/Stochastic_oscillator + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given period to calculate the SR + # @return [Array] Array of hashes with keys(:date_time, :value) + def self.calculate(data, period: 14, signal_period: 3) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period + signal_period - 1) + + data = data.sort_by_hash_date_time_asc + + high_low_values = [] + output = [] + sr_values = [] + + data.each do |v| + high_low_values << { high: v[:high], low: v[:low] } + + if high_low_values.size == period + lowest_low = high_low_values.map { |hlv| hlv[:low] }.min + highest_high = high_low_values.map { |hlv| hlv[:high] }.max + + sr = (v[:close] - lowest_low) / (highest_high - lowest_low) * 100.00 + + sr_values << sr + + if sr_values.size == signal_period + signal = sr_values.average + + output << { + date_time: v[:date_time], + value: { + sr: sr, + sr_signal: signal + } + } + + sr_values.shift + end + + high_low_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb new file mode 100644 index 0000000..04b2c29 --- /dev/null +++ b/lib/technical_analysis/indicators/trix.rb @@ -0,0 +1,61 @@ +module TechnicalAnalysis + class Trix + + # Calculates the triple exponential average (Trix) for the data over the given period + # https://en.wikipedia.org/wiki/Trix_(technical_analysis) + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the EMA for Trix + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 15, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, ((period * 3) - 1)) + + data = data.sort_by_hash_date_time_asc + + ema1 = [] + ema2 = [] + ema3 = [] + output = [] + period_values = [] + + data.each do |v| + price = v[price_key] + period_values << price + + if period_values.size == period + ema1_value = StockCalculation.ema(price, period_values, period, ema1.last) + ema1 << ema1_value + + if ema1.size == period + ema2_value = StockCalculation.ema(ema1_value, ema1, period, ema2.last) + ema2 << ema2_value + + if ema2.size == period + ema3_value = StockCalculation.ema(ema2_value, ema2, period, ema3.last) + ema3 << ema3_value + + if ema3.size == 2 + prev_ema3, current_ema3 = ema3 + trix = ((current_ema3 - prev_ema3) / prev_ema3) + output << { date_time: v[:date_time], value: trix } + + ema3.shift + end + + ema2.shift + end + + ema1.shift + end + + period_values.shift + end + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb new file mode 100644 index 0000000..ea4ea07 --- /dev/null +++ b/lib/technical_analysis/indicators/tsi.rb @@ -0,0 +1,69 @@ +module TechnicalAnalysis + class Tsi + + # Calculates the true strenth index for the data over the given period + # https://en.wikipedia.org/wiki/True_strength_index + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param high_period [Integer] The given high period to calculate the EMA + # @param low_period [Integer] The given low period to calculate the EMA + # @param price_key [Symbol] The hash key for the price data. Default :value + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) + Validation.validate_numeric_data(data, price_key) + Validation.validate_length(data, low_period + high_period) + + data = data.sort_by_hash_date_time_asc + + high_emas = [] + high_multiplier = (2.0 / (high_period + 1.0)) + low_emas = [] + low_multiplier = (2.0 / (low_period + 1.0)) + momentum_values = [] + output = [] + prev_price = data.shift[price_key] + + data.each do |v| + current_price = v[price_key] + momentum = current_price - prev_price + momentum_hash = { value: momentum, abs_value: momentum.abs } + + momentum_values << momentum_hash + + if momentum_values.size == high_period + high_emas << process_ema(momentum_hash, momentum_values, high_multiplier, high_period, high_emas) + + if high_emas.size == low_period + low_ema = process_ema(high_emas.last, high_emas, low_multiplier, low_period, low_emas) + low_emas << low_ema + + output << { date_time: v[:date_time], value: ((100 * (low_ema[:value] / low_ema[:abs_value]))) } + + low_emas.shift if low_emas.size > 1 # Only need to retain the last low_ema + high_emas.shift + end + + momentum_values.shift + end + + prev_price = current_price + end + + output + end + + def self.process_ema(current_value, data, multiplier, period, store) + if store.empty? + value = data.map { |d| d[:value] }.average + abs_value = data.map { |d| d[:abs_value] }.average + else + prev_value = store.last + value = ((multiplier * (current_value[:value] - prev_value[:value])) + prev_value[:value]) + abs_value = ((multiplier * (current_value[:abs_value] - prev_value[:abs_value])) + prev_value[:abs_value]) + end + + { value: value, abs_value: abs_value } + end + + end +end diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb new file mode 100644 index 0000000..eb2c927 --- /dev/null +++ b/lib/technical_analysis/indicators/uo.rb @@ -0,0 +1,60 @@ +module TechnicalAnalysis + class Uo + + # Calculates the ultimate oscillator for the data over the given period + # https://en.wikipedia.org/wiki/Ultimate_oscillator + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param short_period [Integer] The given short period + # @param medium_period [Integer] The given medium period + # @param long_period [Integer] The given long period + # @param short_weight [Float] Weight of short Buying Pressure average for UO + # @param medium_weight [Float] Weight of medium Buying Pressure average for UO + # @param long_weight [Float] Weight of long Buying Pressure average for UO + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, long_period + 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + prior_close = data.shift[:close] + sum_of_weights = [short_weight, medium_weight, long_weight].sum + + data.each do |v| + min_low_p_close = [v[:low], prior_close].min + max_high_p_close = [v[:high], prior_close].max + + buying_pressure = v[:close] - min_low_p_close + true_range = max_high_p_close - min_low_p_close + + period_values << { buying_pressure: buying_pressure, true_range: true_range } + + if period_values.size == long_period + short_average = calculate_average(short_period, period_values) + medium_average = calculate_average(medium_period, period_values) + long_average = calculate_average(long_period, period_values) + uo = 100 * (((short_weight * short_average) + (medium_weight * medium_average) + (long_weight * long_average)) / (sum_of_weights)) + + output << { date_time: v[:date_time], value: uo } + + period_values.shift + end + + prior_close = v[:close] + end + + output + end + + def self.calculate_average(period, data) + buying_pressures_sum = data.last(period).map { |d| d[:buying_pressure] }.sum + true_ranges_sum = data.last(period).map { |d| d[:true_range] }.sum + + buying_pressures_sum / true_ranges_sum + end + + end +end diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb new file mode 100644 index 0000000..8b102e1 --- /dev/null +++ b/lib/technical_analysis/indicators/vi.rb @@ -0,0 +1,50 @@ +module TechnicalAnalysis + class Vi + + # Calculates the vortex indicatorfor the data over the given period + # https://en.wikipedia.org/wiki/Vortex_indicator + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given period to calculate the VI + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period + 1) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + prev_price = data.shift + + data.each do |v| + positive_vm = (v[:high] - prev_price[:low]).abs + negative_vm = (v[:low] - prev_price[:high]).abs + tr = [(v[:high] - v[:low]), (v[:high] - prev_price[:close]).abs, (v[:low] - prev_price[:close]).abs].max + + period_values << { pos_vm: positive_vm, neg_vm: negative_vm, tr: tr } + + if period_values.size == period + pos_vm_period = period_values.map { |pv| pv[:pos_vm] }.sum + neg_vm_period = period_values.map { |pv| pv[:neg_vm] }.sum + tr_period = period_values.map { |pv| pv[:tr] }.sum + + output << { + date_time: v[:date_time], + value: { + positive_vi: (pos_vm_period / tr_period), + negative_vi: (neg_vm_period / tr_period), + } + } + + period_values.shift + end + + prev_price = v + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb new file mode 100644 index 0000000..096098b --- /dev/null +++ b/lib/technical_analysis/indicators/vpt.rb @@ -0,0 +1,30 @@ +module TechnicalAnalysis + class Vpt + + # Calculates the volume-price trend (VPT) for the data + # https://en.wikipedia.org/wiki/Volume%E2%80%93price_trend + # + # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data) + Validation.validate_numeric_data(data, :close, :volume) + Validation.validate_length(data, 2) + + data = data.sort_by_hash_date_time_asc + + output = [] + prev_price = data.shift + prev_pvt = 0 + + data.each do |v| + pvt = prev_pvt + (((v[:close] - prev_price[:close]) / prev_price[:close]) * v[:volume]) + output << { date_time: v[:date_time], value: pvt } + prev_price = v + prev_pvt = pvt + end + + output + end + + end +end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb new file mode 100644 index 0000000..eb521c1 --- /dev/null +++ b/lib/technical_analysis/indicators/wr.rb @@ -0,0 +1,38 @@ +module TechnicalAnalysis + class Wr + + # Calculates the Williams %R for the data over the given period + # https://en.wikipedia.org/wiki/Williams_%25R + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param period [Integer] The given look-back period to calculate the Williams %R + # @return [Hash] A hash of the results with keys (:date_time, :value) + def self.calculate(data, period: 14) + Validation.validate_numeric_data(data, :high, :low, :close) + Validation.validate_length(data, period) + + data = data.sort_by_hash_date_time_asc + + output = [] + period_values = [] + + data.each do |v| + period_values << { high: v[:high], low: v[:low] } + + if period_values.size == period + lowest_low = period_values.map { |pv| pv[:low] }.min + highest_high = period_values.map { |pv| pv[:high] }.max + + wr = (highest_high - v[:close]) / (highest_high - lowest_low) * -100 + + output << { date_time: v[:date_time], value: wr } + + period_values.shift + end + end + + output + end + + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..ff4e025 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,26 @@ +require 'csv' + +class SpecHelper + + TEST_DATA_PATH = File.join(File.dirname(__FILE__),'ta_test_data.csv') + FLOAT_KEYS = [:open, :high, :low, :close].freeze + INTEGER_KEYS = [:volume].freeze + + def self.get_test_data(*columns) + @data = CSV.read(TEST_DATA_PATH, headers: true) + columns = columns.map(&:to_sym) + output = [] + @data.each do |v| + col_hash = { date_time: v["date_time"] } + columns.each do |col| + value = v[col.to_s] + value = value.to_f if FLOAT_KEYS.include?(col) + value = value.to_i if INTEGER_KEYS.include?(col) + col_hash[col] = value + end + output << col_hash + end + output + end + +end diff --git a/spec/ta_test_data.csv b/spec/ta_test_data.csv new file mode 100644 index 0000000..8524dca --- /dev/null +++ b/spec/ta_test_data.csv @@ -0,0 +1,64 @@ +date_time,close,volume,open,high,low +"2019-01-09T00:00:00.000Z",153.3100,45034370.0000,151.2900,154.5300,149.6300 +"2019-01-08T00:00:00.000Z",150.7500,40622910.0000,149.5600,151.8200,148.5200 +"2019-01-07T00:00:00.000Z",147.9300,54571440.0000,148.7000,148.8300,145.9000 +"2019-01-04T00:00:00.000Z",148.2600,57423650.0000,144.5300,148.5499,143.8000 +"2019-01-03T00:00:00.000Z",142.1900,91106840.0000,143.9800,145.7200,142.0000 +"2019-01-02T00:00:00.000Z",157.9200,35637070.0000,154.8900,158.8500,154.2300 +"2018-12-31T00:00:00.000Z",157.7400,34499390.0000,158.5300,159.3600,156.4800 +"2018-12-28T00:00:00.000Z",156.2300,41740600.0000,157.5000,158.5200,154.5500 +"2018-12-27T00:00:00.000Z",156.1500,51608850.0000,155.8400,156.7700,150.0700 +"2018-12-26T00:00:00.000Z",157.1700,58133850.0000,148.3000,157.2300,146.7200 +"2018-12-24T00:00:00.000Z",146.8300,37169230.0000,148.1500,151.5500,146.5900 +"2018-12-21T00:00:00.000Z",150.7300,95497900.0000,156.8600,158.1600,149.6300 +"2018-12-20T00:00:00.000Z",156.8300,64398230.0000,160.4000,162.1100,155.3000 +"2018-12-19T00:00:00.000Z",160.8900,47597670.0000,166.0000,167.4500,159.0900 +"2018-12-18T00:00:00.000Z",166.0700,33753490.0000,165.3800,167.5300,164.3900 +"2018-12-17T00:00:00.000Z",163.9400,43250420.0000,165.4500,168.3500,162.7300 +"2018-12-14T00:00:00.000Z",165.4800,40620360.0000,169.0000,169.0800,165.2800 +"2018-12-13T00:00:00.000Z",170.9500,31754210.0000,170.4900,172.5700,169.5500 +"2018-12-12T00:00:00.000Z",169.1000,35474680.0000,170.4000,171.9200,169.0200 +"2018-12-11T00:00:00.000Z",168.6300,45968040.0000,171.6600,171.7900,167.0000 +"2018-12-10T00:00:00.000Z",169.6000,61759000.0000,165.0000,170.0900,163.3300 +"2018-12-07T00:00:00.000Z",168.4900,41678680.0000,173.4900,174.4900,168.3000 +"2018-12-06T00:00:00.000Z",174.7200,42704910.0000,171.7600,174.7800,170.4200 +"2018-12-04T00:00:00.000Z",176.6900,41141250.0000,180.9500,182.3899,176.2700 +"2018-12-03T00:00:00.000Z",184.8200,40537700.0000,184.4600,184.9400,181.2100 +"2018-11-30T00:00:00.000Z",178.5800,39424260.0000,180.2900,180.3300,177.0300 +"2018-11-29T00:00:00.000Z",179.5500,41523580.0000,182.6600,182.8000,177.7000 +"2018-11-28T00:00:00.000Z",180.9400,45941750.0000,176.7300,181.2900,174.9300 +"2018-11-27T00:00:00.000Z",174.2400,41156140.0000,171.5100,174.7700,170.8800 +"2018-11-26T00:00:00.000Z",174.6200,44662320.0000,174.2400,174.9500,170.2600 +"2018-11-23T00:00:00.000Z",172.2900,23623970.0000,174.9400,176.5950,172.1000 +"2018-11-21T00:00:00.000Z",176.7800,31096240.0000,179.7300,180.2700,176.5500 +"2018-11-20T00:00:00.000Z",176.9800,67678680.0000,178.3700,181.4700,175.5100 +"2018-11-19T00:00:00.000Z",185.8600,41626820.0000,190.0000,190.7000,184.9900 +"2018-11-16T00:00:00.000Z",193.5300,36191330.0000,190.5000,194.9695,189.4600 +"2018-11-15T00:00:00.000Z",191.4100,46271660.0000,188.3900,191.9700,186.9000 +"2018-11-14T00:00:00.000Z",186.8000,60547340.0000,193.9000,194.4800,185.9300 +"2018-11-13T00:00:00.000Z",192.2300,46725710.0000,191.6300,197.1800,191.4501 +"2018-11-12T00:00:00.000Z",194.1700,50991030.0000,199.0000,199.8500,193.7900 +"2018-11-09T00:00:00.000Z",204.4700,34317760.0000,205.5500,206.0100,202.2500 +"2018-11-08T00:00:00.000Z",208.4900,25289270.0000,209.9800,210.1200,206.7500 +"2018-11-07T00:00:00.000Z",209.9500,33291640.0000,205.9700,210.0600,204.1300 +"2018-11-06T00:00:00.000Z",203.7700,31774720.0000,201.9200,204.7200,201.6900 +"2018-11-05T00:00:00.000Z",201.5900,66072170.0000,204.3000,204.3900,198.1700 +"2018-11-02T00:00:00.000Z",207.4800,91046560.0000,209.5500,213.6500,205.4300 +"2018-11-01T00:00:00.000Z",222.2200,52954070.0000,219.0500,222.3600,216.8100 +"2018-10-31T00:00:00.000Z",218.8600,38016810.0000,216.8800,220.4500,216.6200 +"2018-10-30T00:00:00.000Z",213.3000,36487930.0000,211.1500,215.1800,209.2700 +"2018-10-29T00:00:00.000Z",212.2400,45713690.0000,219.1900,219.6900,206.0900 +"2018-10-26T00:00:00.000Z",216.3000,47191700.0000,215.9000,220.1900,212.6700 +"2018-10-25T00:00:00.000Z",219.8000,29027340.0000,217.7100,221.3800,216.7500 +"2018-10-24T00:00:00.000Z",215.0900,39992120.0000,222.6000,224.2300,214.5400 +"2018-10-23T00:00:00.000Z",222.7300,38681170.0000,215.8300,223.2500,214.7000 +"2018-10-22T00:00:00.000Z",220.6500,28751540.0000,219.7900,223.3600,218.9400 +"2018-10-19T00:00:00.000Z",219.3100,32874330.0000,218.0600,221.2600,217.4300 +"2018-10-18T00:00:00.000Z",216.0200,32389280.0000,217.8600,219.7400,213.0000 +"2018-10-17T00:00:00.000Z",221.1900,22692880.0000,222.3000,222.6400,219.3400 +"2018-10-16T00:00:00.000Z",222.1500,28802550.0000,218.9300,222.9900,216.7627 +"2018-10-15T00:00:00.000Z",217.3600,30280450.0000,221.1600,221.8300,217.2700 +"2018-10-12T00:00:00.000Z",222.1100,39494770.0000,220.4200,222.8800,216.8400 +"2018-10-11T00:00:00.000Z",214.4500,52902320.0000,214.5200,219.5000,212.3200 +"2018-10-10T00:00:00.000Z",216.3600,41084070.0000,225.4600,226.3500,216.0500 +"2018-10-09T00:00:00.000Z",226.8700,26656630.0000,223.6400,227.2700,222.2462 diff --git a/spec/technical_analysis/indicators/adi_spec.rb b/spec/technical_analysis/indicators/adi_spec.rb new file mode 100644 index 0000000..ea56856 --- /dev/null +++ b/spec/technical_analysis/indicators/adi_spec.rb @@ -0,0 +1,83 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "ADI" do + + describe 'Accumulation/Distribution Index' do + it 'Calculates ADI' do + + input_data = SpecHelper.get_test_data(:volume, :high, :low, :close) + output = TechnicalAnalysis::Adi.calculate(input_data) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>22411774.711174767}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-16199273.599504825}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-37713866.134323865}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-8288954.710482582}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-37374123.7894299}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-16341921.130974408}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-13591269.009762233}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-16955140.819851194}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-17555977.138388995}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-24060850.441556394}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>9915241.57013943}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-25537009.286413625}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-16320985.571510637}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-17952613.497042313}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-22322304.45292461}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-9048353.606900878}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-2596414.5729579534}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>47686098.74235708}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>2052056.5039138943}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>8638028.433174696}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>20488006.51898352}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>52544543.51729703}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>53370009.30364728}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>59576412.70790268}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>14980297.36136794}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-19025685.861899547}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-67251111.0548819}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-31201198.431607798}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13921718.702957403}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-42863658.35269459}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-77157217.68155372}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-104408223.70305927}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-126035061.64521725}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-87657844.24649628}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-57716487.89688186}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-16831219.815120786}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-28229849.61904212}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30619198.70995107}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>7310177.429459017}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28184142.065140743}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>13345403.439446371}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-25774650.00158758}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>27031122.187761355}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>12348220.058324995}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21169236.217537448}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-23482456.813564237}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-59826989.44514345}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-84453563.11062376}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-82088668.90680213}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-109189734.6005822}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-144651314.99705797}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-215519041.4917826}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-249091249.23371798}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-191621153.9435182}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-149563792.60023466}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-155977335.67328295}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-160289759.42328274}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-139000081.24146464}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-220800308.5532927}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-170386118.17770624}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-149339794.90125585}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-135060226.53761944}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-112451134.66006838} + ] + + expect(output).to eq(expected_output) + end + end + end +end diff --git a/spec/technical_analysis/indicators/adtv_spec.rb b/spec/technical_analysis/indicators/adtv_spec.rb new file mode 100644 index 0000000..5cc33a4 --- /dev/null +++ b/spec/technical_analysis/indicators/adtv_spec.rb @@ -0,0 +1,65 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "ADTV" do + input_data = SpecHelper.get_test_data(:volume) + + describe 'Average Daily Trading Volume' do + it 'Calculates ADTV (22 day)' do + output = TechnicalAnalysis::Adtv.calculate(input_data, period: 22, volume_key: :volume) + + expected_output = [ + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40280851.81818182}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>40218699.09090909}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>39911139.54545455}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>39824262.72727273}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>40152941.81818182}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>41528709.54545455}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>42322760.0}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>42936325.90909091}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>43356214.09090909}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>44938230.0}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>45044807.27272727}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>44360389.09090909}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>44572670.90909091}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>45123980.0}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>45067164.09090909}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>44876704.54545455}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>45010174.09090909}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>45124760.0}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>44587813.63636363}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>42390465.90909091}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>41281670.90909091}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>42644592.72727273}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>43220792.72727273}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43683765.90909091}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>43567240.90909091}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43095846.81818182}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>42937879.09090909}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>41719976.81818182}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>41780250.0}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>43062381.81818182}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>45511067.27272727}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>44124274.09090909}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>45353256.36363637}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>46625296.36363637}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>46492490.90909091}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46189911.36363637}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>45721516.81818182}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>47975301.36363637}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>48793455.45454545}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>49431352.72727273}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>49407791.81818182}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>49513676.36363637} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Adtv.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/adx_spec.rb b/spec/technical_analysis/indicators/adx_spec.rb new file mode 100644 index 0000000..a37197a --- /dev/null +++ b/spec/technical_analysis/indicators/adx_spec.rb @@ -0,0 +1,59 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "ADX" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Average Directional Index' do + it 'Calculates ADX (14 day)' do + output = TechnicalAnalysis::Adx.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:adx=>48.08801057392937, :di_neg=>35.92768510004254, :di_pos=>16.527665969119678}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Adx.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/ao_spec.rb b/spec/technical_analysis/indicators/ao_spec.rb new file mode 100644 index 0000000..b0313ee --- /dev/null +++ b/spec/technical_analysis/indicators/ao_spec.rb @@ -0,0 +1,53 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "AO" do + input_data = SpecHelper.get_test_data(:high, :low) + + describe 'Awesome Oscillator' do + it 'Calculates AO (5 day short period, 34 day long period)' do + output = TechnicalAnalysis::Ao.calculate(input_data, short_period: 5, long_period: 34) + + expected_output = [ + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-28.26261029411762}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-29.739166176470576}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-28.547813235294086}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-27.130989705882314}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-25.05331323529407}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-21.886519117646998}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-19.392987941176415}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-19.071752647058815}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-19.51995852941178}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-20.365870294117656}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-21.579664411764696}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21.92503676470585}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-20.811713235294178}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-20.12868382352943}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18.865919117647138}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18.17262500000004}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-18.17277205882357}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-18.88406617647061}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-19.609007352941205}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-21.124477941176536}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.471330882352987}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.97706617647063}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.924007352941203}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-19.633272058823536}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-16.73956617647059}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-16.804919117647017}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-16.838043823529347}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-17.41204382352936}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-17.8071908823529}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-17.518757058823525}, + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Ao.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/atr_spec.rb b/spec/technical_analysis/indicators/atr_spec.rb new file mode 100644 index 0000000..9d85ddb --- /dev/null +++ b/spec/technical_analysis/indicators/atr_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "ATR" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Average True Range' do + it 'Calculates ATR (14 day)' do + output = TechnicalAnalysis::Atr.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>7.449807142857144}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>7.339820918367347}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>7.326262281341107}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>7.199386404102457}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>7.884430232380852}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>7.98625664435365}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>7.63938116975696}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>7.542996800488605}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>7.244925600453705}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>7.173145200421298}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>7.423634828962634}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>7.302653769751019}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>7.391749929054517}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>7.233053505550622}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>7.109942540868436}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>7.212089502234975}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>7.43622596636105}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>7.1707812544781175}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>6.9928683077296805}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>6.828377714320418}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>6.618493591868961}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>6.649315478164034}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>6.538650086866604}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>6.307317937804704}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>6.311080942247224}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>6.471003732086706}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>6.456646322651943}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>6.4540287281768025}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>6.475883819021315}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>6.355463546234078}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>6.1365018643602145}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>5.946037445477343}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>5.926320485086102}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>5.904440450437095}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>5.739123275405874}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>5.926328755734025}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>5.989448130324453}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>6.170916121015564}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>6.084422112371596}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>6.400534818630767}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>6.450496617299998}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>6.273318287492855}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>6.048795552671939}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>5.946738727481086}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>6.6591145326610075}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>6.637742066042365}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>6.3729033470393395}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>6.195553107965099}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>6.103013600253306} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Atr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/bb_spec.rb b/spec/technical_analysis/indicators/bb_spec.rb new file mode 100644 index 0000000..d948401 --- /dev/null +++ b/spec/technical_analysis/indicators/bb_spec.rb @@ -0,0 +1,67 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "BB" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Bollinger Bands' do + it 'Calculates BB (20, 2)' do + output = TechnicalAnalysis::Bb.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close) + + expected_output = [ + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>141.07714470666247, :middle_band=>158.1695, :upper_band=>175.26185529333753}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Bb.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/cci_spec.rb b/spec/technical_analysis/indicators/cci_spec.rb new file mode 100644 index 0000000..ba164de --- /dev/null +++ b/spec/technical_analysis/indicators/cci_spec.rb @@ -0,0 +1,67 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "CCI" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Commodity Channel Index' do + it 'Calculates CCI (20 day)' do + output = TechnicalAnalysis::Cci.calculate(input_data, period: 20, constant: 0.015) + + expected_output = [ + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-281.5255251804358}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-198.71238766942466}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-107.40409620543349}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-88.26723659204252}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-121.3842764199079}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-179.88996064655686}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-170.11758119513328}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-176.53554346437872}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-144.29736082195598}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-109.8703962546515}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-129.79321417259732}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-166.092016017792}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-143.70909871161282}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-145.81148745067057}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-130.57777507098388}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-117.06521007698558}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-79.16162769465076}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-67.42425893465922}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-68.8774176049022}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-32.43699792850786}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-60.69535791887537}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-87.66403875835518}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-102.13101656480995}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-118.83020945347108}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-105.1287325078536}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-93.5619842292165}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-77.37092752385674}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-114.79798652194032}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-123.22931274779911}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-108.36683776743406}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-145.86611021295013}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-175.655233047097}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-204.3001270602558}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-205.86763488625635}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-130.89740843118958}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-109.82143904961333}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-82.72457326337747}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-62.94237272962061}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-62.42850721332871}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-162.69069349674928}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-119.01911861945885}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-103.45330536502108}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-72.7408611895969}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-48.14847062019609} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Cci.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/cmf_spec.rb b/spec/technical_analysis/indicators/cmf_spec.rb new file mode 100644 index 0000000..cf0f3e3 --- /dev/null +++ b/spec/technical_analysis/indicators/cmf_spec.rb @@ -0,0 +1,67 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "CMF" do + input_data = SpecHelper.get_test_data(:high, :low, :close, :volume) + + describe 'Chaikin Money Flow' do + it 'Calculates CMF (20 day)' do + output = TechnicalAnalysis::Cmf.calculate(input_data, period: 20) + + expected_output = [ + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>0.010519910116535688}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.002328367522189358}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.0839939173853672}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>0.11517576782439708}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>0.08638139363431603}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>0.06492697386482489}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.00325588286845078}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.06224056395025631}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.016262278292090777}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.004132959703610273}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.02107439975862456}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.09451983283878523}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0864519745264971}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.12097582444999905}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.07707518115228632}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.039334642581608396}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.008559410227273146}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.02808273355873217}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.08707816577338795}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.006195178249247199}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044697234566322144}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.008556645577315109}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.09289096149170357}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.02994416009907359}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.05299093511730075}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.041279122544240626}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.005177700749048257}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>0.008829457014340984}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0635610565928198}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.08160027269601758}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.07883316711924936}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.08053545285645361}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.12311876857928804}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.13433878933016613}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.11185040161958644}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.09771633750350824}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.14870217725852253}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.1421967277504723}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.1171779554311941}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.23384083275693518}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.14338098793972473}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.16209459049078995}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.10900349402409147}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.14148236474171028} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Cmf.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/cr_spec.rb b/spec/technical_analysis/indicators/cr_spec.rb new file mode 100644 index 0000000..1e93b59 --- /dev/null +++ b/spec/technical_analysis/indicators/cr_spec.rb @@ -0,0 +1,86 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "CR" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Cumulative Return' do + it 'Calculates CR' do + output = TechnicalAnalysis::Cr.calculate(input_data, price_key: :close) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.04632608983118081}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.054745008154449756}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-0.02098117864856522}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.041918279190725924}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-0.02080486622294706}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.025036364437783783}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.04782474544893549}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-0.03332304844183895}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-0.027416582183629384}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-0.018248336051483294}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.05192400934455856}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-0.031163221228016014}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.046590558469608113}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.06448626966985496}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-0.05981399039097277}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-0.035306563230043594}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-0.020496319478115244}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0854674483184203}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.11142945299069952}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.10182042579450784}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-0.07458015603649674}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.08101555957156079}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.09873495834618948}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.14413540794287485}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.15268656058535732}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.17662097236302726}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.15630096531053028}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-0.14695640675276592}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.18076431436505483}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.21990567285229431}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.22078723498038524}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.24057830475602773}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.2303081059637678}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.23198307400714063}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.20245074271609295}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.20857759950632518}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.2128531758275664}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-0.185348437431128}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.2211839379380262}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.22986732489972234}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.25732798518975625}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.2524353153788514}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.2567108917000926}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.2546392206990788}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.2464847710142373}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.2705954952175255}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.277383523603826}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.2679948869396571}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.29082734605721344}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.3087230572574602}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.3356107021642351}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.35280116366200903}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.3072244016397056}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.3117203684929695}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.3113677436417332}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.30471194957464626}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.30391854365936444}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.3732534050337198}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.34649799444615864}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.34795257195750867}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.33552254595142594}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.3242385507118614} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Cr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/dc_spec.rb b/spec/technical_analysis/indicators/dc_spec.rb new file mode 100644 index 0000000..3406351 --- /dev/null +++ b/spec/technical_analysis/indicators/dc_spec.rb @@ -0,0 +1,67 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "DC" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Donchian Channel' do + it 'Calculates DC (20 day)' do + output = TechnicalAnalysis::Dc.calculate(input_data, period: 20, price_key: :close) + + expected_output = [ + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>226.87}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:lower_bound=>194.17, :upper_bound=>222.73}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:lower_bound=>192.23, :upper_bound=>222.73}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:lower_bound=>185.86, :upper_bound=>222.73}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:lower_bound=>176.98, :upper_bound=>222.22}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:lower_bound=>176.78, :upper_bound=>222.22}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>208.49}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>204.47}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>194.17}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:lower_bound=>165.48, :upper_bound=>193.53}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>193.53}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>185.86}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:lower_bound=>160.89, :upper_bound=>184.82}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:lower_bound=>156.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:lower_bound=>150.73, :upper_bound=>184.82}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>176.69}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>174.72}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Dc.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/dlr_spec.rb b/spec/technical_analysis/indicators/dlr_spec.rb new file mode 100644 index 0000000..b6452f5 --- /dev/null +++ b/spec/technical_analysis/indicators/dlr_spec.rb @@ -0,0 +1,86 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "DLR" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Daily Log Return' do + it 'Calculates Daily Log Return' do + output = TechnicalAnalysis::Dlr.calculate(input_data, price_key: :close) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.047433479205543055}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.008867076040336814}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.03509614368752819}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021617789532325248}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.02179786426382509}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.0043307687122485835}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023651064679340767}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.01511525802908552}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006091481696142526}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009382539847836957}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.03490373037505153}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021661496781179467}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.0160517090105079}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018948623129528868}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004981915647820579}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.025732630512992103}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015235626165565584}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0686329326726632}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028799017690867113}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010755975020512992}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.029877500317357083}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006978328672237313}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.01946981300300202}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.051687201448600596}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.010041492241593453}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.028654045970026604}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.024379198463276127}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011014814954241668}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.04043883708306672}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.04895697028998929}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011307102064021337}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.02572691808848715}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013433080838346925}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.002178525198011193}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.037731825412945244}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.007711763925503673}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005417040583021469}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.034345698370823956}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044985593831335616}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011212092072018474}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03630829170624626}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.00656632250750863}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.00573575767570937}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.002783290222441408}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010880860180775654}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.032520774492099586}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0093498343683261}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.012908878993777004}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.03168848455571821}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.02555848551661011}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.039672259323895565}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.026214701847591528}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.06805256711339175}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006510938359150324}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.0005121966947240164}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009618827546033224}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011404677153263752}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.10492438427688831}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.04180329782029066}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022283003244291597}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.01888364670315034}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01683917971506794} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Dlr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/dpo_spec.rb b/spec/technical_analysis/indicators/dpo_spec.rb new file mode 100644 index 0000000..d7880f3 --- /dev/null +++ b/spec/technical_analysis/indicators/dpo_spec.rb @@ -0,0 +1,57 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "DPO" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Detrended Price Oscillator' do + it 'Calculates DPO (20 day)' do + output = TechnicalAnalysis::Dpo.calculate(input_data, period: 20, price_key: :close) + + expected_output = [ + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-31.444000000000017}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-39.16900000000004}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-39.04850000000002}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-43.2405}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-40.02850000000001}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-39.24899999999997}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-31.052999999999997}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-30.723499999999945}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30.462999999999965}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-22.93399999999997}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-29.3245}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-29.007000000000033}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-33.321500000000015}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.836000000000013}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-28.722000000000037}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-26.35200000000006}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-22.884000000000043}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-26.388500000000022}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-25.746500000000054}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-22.48350000000005}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-26.41850000000005}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-29.025999999999982}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-33.053}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-35.0085}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.876499999999993}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.642999999999972}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.498999999999995}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-18.922999999999973}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-17.36949999999996}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31.726499999999987}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-24.407999999999987}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-23.730500000000006}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-19.607999999999976}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-15.774999999999977} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Dpo.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/dr_spec.rb b/spec/technical_analysis/indicators/dr_spec.rb new file mode 100644 index 0000000..2f46097 --- /dev/null +++ b/spec/technical_analysis/indicators/dr_spec.rb @@ -0,0 +1,86 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "DR" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Daily Return' do + it 'Calculates Daily Return' do + output = TechnicalAnalysis::Dr.calculate(input_data, price_key: :close) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.046326089831180806}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.00882787946015906}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.035719281883889176}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021385799828913643}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.022037173352962736}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.004321404456448352}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023373570233735652}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.015230071289695335}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006110072500113972}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009426693859052815}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.034301620796480026}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021897810218978186}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.015923566878980888}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018770226537216828}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004994346023369678}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.026066572902015972}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015352279996344587}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.06633066330663306}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028388278388278287}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010814028473634663}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.030328311331403013}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006954036675398845}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.019281500311765565}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.05037413801535684}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.009991244785497289}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.02824741195442948}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.02467880085653107}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011075701374013924}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.03963209838267967}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.047777897342085596}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011300711944851605}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.025398800769317886}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013523710023797264}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.0021761539342571856}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.038452708907254385}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.0076821045650491415}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005402394876079075}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.03494232276850706}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.043988745806730845}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011149470824608043}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03565705128205121}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.006587928066947413}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.005719339622641484}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.0027871671707289103}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010940272028385545}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.031997660134542305}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.009306260575296044}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.01299255825301926}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.031191666164870235}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.025234632357511222}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.038895619460562525}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.02587407947986453}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.07042157597221266}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006489788127505114}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.00051232788984934}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009665237150355388}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011411182959297772}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.09960739614994929}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.042689359307968244}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022258195062726527}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.019063070371121427}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01698175787728018} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Dr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/eom_spec.rb b/spec/technical_analysis/indicators/eom_spec.rb new file mode 100644 index 0000000..6e9cece --- /dev/null +++ b/spec/technical_analysis/indicators/eom_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "EoM" do + input_data = SpecHelper.get_test_data(:high, :low, :volume) + + describe 'Ease of Movement' do + it 'Calculates EoM (14 day)' do + output = TechnicalAnalysis::Eom.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Eom.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb new file mode 100644 index 0000000..7827ebc --- /dev/null +++ b/spec/technical_analysis/indicators/evm_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "EVM" do + input_data = SpecHelper.get_test_data(:high, :low, :volume) + + describe 'Ease of Movement' do + it 'Calculates EVM (14 day)' do + output = TechnicalAnalysis::Evm.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Evm.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/fi_spec.rb b/spec/technical_analysis/indicators/fi_spec.rb new file mode 100644 index 0000000..1678990 --- /dev/null +++ b/spec/technical_analysis/indicators/fi_spec.rb @@ -0,0 +1,85 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "FI" do + input_data = SpecHelper.get_test_data(:close, :volume) + + describe 'Forced Index' do + it 'Calculates FI' do + output = TechnicalAnalysis::Fi.calculate(input_data) + + expected_output = [ + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-431793575.69999963}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-101043431.20000133}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>302529938.200001}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-143832137.5}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>137964214.49999976}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-21785164.80000018}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-167452577.5999996}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>108156545.69999973}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>38527063.6000001}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>80456833.59999938}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-305539796.7999995}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>136718771.40000024}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-165170950.0}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-185597581.4000001}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>38677205.80000009}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>211373463.60000008}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>177925675.1999992}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-1342026294.4000008}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-389165081.2999991}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>69268889.60000022}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>205742335.19999927}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-36922334.19999948}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-137957395.20000035}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-525207609.0000006}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-90647877.39999989}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-328772056.1999987}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>213312352.5999993}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>76725619.60000016}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-319277709.3999995}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-600986678.4000016}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-6219247.999999646}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-106071625.30000022}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>104063205.60000056}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-15639333.199999813}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>307809724.99999946}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-57717776.19999944}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-38241532.19999996}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>252955247.99999923}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-334478362.4999998}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-84128672.69999996}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-259658176.39999956}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>68552489.99999909}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-44588998.799999945}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>16673099.59999996}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>58745288.49999982}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-222193369.19999996}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-66605646.799999654}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>71894933.69999984}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-246555930.60000032}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-261456813.7999983}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-582537190.0000021}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-144959996.99999917}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>601104008.9999986}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-52641026.99999906}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>3339247.9999993355}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>52094078.90000067}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>6414672.59999923}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-1433110593.199999}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>348561555.4999996}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-18008575.19999913}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>114556606.19999972}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>115287987.2000001} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Fi.calculate([])}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb new file mode 100644 index 0000000..8f3507e --- /dev/null +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -0,0 +1,62 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "Ichimoku" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Ichimoku' do + it 'Calculates Ichimoku' do + output = TechnicalAnalysis::Ichimoku.calculate(input_data, low_period: 3, medium_period: 10, high_period: 20) + + expected_output = [ + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:chikou_span=>201.59, :kijun_sen=>198.025, :senkou_span_a=>210.7325, :senkou_span_b=>212.72, :tenkan_sen=>190.44975}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:chikou_span=>203.77, :kijun_sen=>197.555, :senkou_span_a=>208.555, :senkou_span_b=>212.26, :tenkan_sen=>189.97975000000002}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:chikou_span=>209.95, :kijun_sen=>192.815, :senkou_span_a=>207.19, :senkou_span_b=>211.2, :tenkan_sen=>185.23975000000002}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:chikou_span=>208.49, :kijun_sen=>192.815, :senkou_span_a=>208.08499999999998, :senkou_span_b=>211.2, :tenkan_sen=>183.105}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:chikou_span=>204.47, :kijun_sen=>189.055, :senkou_span_a=>208.225, :senkou_span_b=>211.2, :tenkan_sen=>176.785}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:chikou_span=>194.17, :kijun_sen=>185.055, :senkou_span_a=>205.015, :senkou_span_b=>209.01, :tenkan_sen=>175.265}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:chikou_span=>192.23, :kijun_sen=>183.72, :senkou_span_a=>202.81755, :senkou_span_b=>207.84005, :tenkan_sen=>173.4275}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:chikou_span=>186.8, :kijun_sen=>182.61475000000002, :senkou_span_a=>198.51749999999998, :senkou_span_b=>205.07999999999998, :tenkan_sen=>175.77499999999998}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:chikou_span=>191.41, :kijun_sen=>182.61475000000002, :senkou_span_a=>195.6725, :senkou_span_b=>205.07999999999998, :tenkan_sen=>176.84}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:chikou_span=>193.53, :kijun_sen=>182.61475000000002, :senkou_span_a=>194.237375, :senkou_span_b=>205.07999999999998, :tenkan_sen=>178.865}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:chikou_span=>185.86, :kijun_sen=>180.48, :senkou_span_a=>193.76737500000002, :senkou_span_b=>204.61, :tenkan_sen=>180.985}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:chikou_span=>176.98, :kijun_sen=>177.6, :senkou_span_a=>189.027375, :senkou_span_b=>199.87, :tenkan_sen=>180.60500000000002}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:chikou_span=>176.78, :kijun_sen=>177.6, :senkou_span_a=>187.95999999999998, :senkou_span_b=>198.935, :tenkan_sen=>177.68}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:chikou_span=>172.29, :kijun_sen=>176.62, :senkou_span_a=>182.92000000000002, :senkou_span_b=>197.23000000000002, :tenkan_sen=>175.34495}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:chikou_span=>174.62, :kijun_sen=>174.135, :senkou_span_a=>180.16, :senkou_span_b=>196.31, :tenkan_sen=>169.055}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:chikou_span=>174.24, :kijun_sen=>174.135, :senkou_span_a=>178.57375000000002, :senkou_span_b=>196.31, :tenkan_sen=>168.91000000000003}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:chikou_span=>180.94, :kijun_sen=>174.135, :senkou_span_a=>179.194875, :senkou_span_b=>196.31, :tenkan_sen=>167.625}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:chikou_span=>179.55, :kijun_sen=>174.135, :senkou_span_a=>179.727375, :senkou_span_b=>196.31, :tenkan_sen=>169.785}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:chikou_span=>178.58, :kijun_sen=>174.135, :senkou_span_a=>180.739875, :senkou_span_b=>191.95499999999998, :tenkan_sen=>168.925}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:chikou_span=>184.82, :kijun_sen=>173.83499999999998, :senkou_span_a=>180.73250000000002, :senkou_span_b=>190.19, :tenkan_sen=>167.64999999999998}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:chikou_span=>176.69, :kijun_sen=>172.55995000000001, :senkou_span_a=>179.10250000000002, :senkou_span_b=>190.19, :tenkan_sen=>165.905}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:chikou_span=>174.72, :kijun_sen=>166.935, :senkou_span_a=>177.64, :senkou_span_b=>190.19, :tenkan_sen=>163.72}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:chikou_span=>168.49, :kijun_sen=>164.895, :senkou_span_a=>175.98247500000002, :senkou_span_b=>189.21, :tenkan_sen=>161.41500000000002}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:chikou_span=>169.6, :kijun_sen=>161.1, :senkou_span_a=>171.595, :senkou_span_b=>184.67000000000002, :tenkan_sen=>158.54}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:chikou_span=>168.63, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.5225, :senkou_span_b=>181.59, :tenkan_sen=>154.35000000000002}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:chikou_span=>169.1, :kijun_sen=>159.57999999999998, :senkou_span_a=>170.88, :senkou_span_b=>180.255, :tenkan_sen=>152.375}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:chikou_span=>170.95, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.95999999999998, :senkou_span_b=>179.14975, :tenkan_sen=>151.91}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:chikou_span=>165.48, :kijun_sen=>157.835, :senkou_span_a=>171.53, :senkou_span_b=>179.14975, :tenkan_sen=>152.62}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:chikou_span=>163.94, :kijun_sen=>157.47, :senkou_span_a=>170.74249999999998, :senkou_span_b=>178.84975, :tenkan_sen=>154.715}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:chikou_span=>166.07, :kijun_sen=>157.06, :senkou_span_a=>169.23247500000002, :senkou_span_b=>176.71499999999997, :tenkan_sen=>156.79500000000002}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:chikou_span=>160.89, :kijun_sen=>154.725, :senkou_span_a=>165.3275, :senkou_span_b=>172.015, :tenkan_sen=>150.68}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:chikou_span=>156.83, :kijun_sen=>152.055, :senkou_span_a=>163.15500000000003, :senkou_span_b=>170.12, :tenkan_sen=>150.425}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:chikou_span=>150.73, :kijun_sen=>150.68, :senkou_span_a=>159.82, :senkou_span_b=>167.285, :tenkan_sen=>145.41500000000002}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:chikou_span=>146.83, :kijun_sen=>150.68, :senkou_span_a=>156.965, :senkou_span_b=>165.765, :tenkan_sen=>147.81}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + medium_period = 20 + high_period = 40 + size_limit = (medium_period + high_period + 1) + + expect {TechnicalAnalysis::Ichimoku.calculate(input_data, high_period: size_limit)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/kc_spec.rb b/spec/technical_analysis/indicators/kc_spec.rb new file mode 100644 index 0000000..4bc1f8d --- /dev/null +++ b/spec/technical_analysis/indicators/kc_spec.rb @@ -0,0 +1,77 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "KC" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Keltner Channel' do + it 'Calculates KC (10 day)' do + output = TechnicalAnalysis::Kc.calculate(input_data, period: 10) + + expected_output = [ + {:date_time=>"2018-10-22T00:00:00.000Z", :value=> {:lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667}}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=> {:lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664}}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=> {:lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333}}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=> {:lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004}}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=> {:lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667}}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005}}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>146.74034, :middle_band=>151.57433, :upper_band=>156.40832}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Kc.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/kst_spec.rb b/spec/technical_analysis/indicators/kst_spec.rb new file mode 100644 index 0000000..18b50e2 --- /dev/null +++ b/spec/technical_analysis/indicators/kst_spec.rb @@ -0,0 +1,45 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "KST" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Know Sure Thing' do + it 'Calculates KST' do + output = TechnicalAnalysis::Kst.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close) + + expected_output = [ + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-150.14198896419614}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-146.67417088368043}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-143.06704590371226}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-141.6235541026754}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-140.69442915235626}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-141.36803679622636}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-141.34365936138443}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-143.4025404878081}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-145.9029270207904}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-150.769274028613}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-151.25248412993977}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-152.69243922992774}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-154.278039839607}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-152.43337072156913}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-150.77021075475108}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-157.0260814891967}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-157.83675223915662}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-155.71040741442587}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-148.9261153101682}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-140.9140022298261} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + roc4 = 60 + sma4 = 30 + expect {TechnicalAnalysis::Kst.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb new file mode 100644 index 0000000..bbffa99 --- /dev/null +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -0,0 +1,53 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "MACD" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Moving Average Convergence Divergence' do + it 'Calculates MACD (12, 26, 9)' do + output = TechnicalAnalysis::Macd.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close) + + expected_output = [ + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:macd_histogram=>0.4770591535283888, :macd_line=>-8.745173952069024, :signal_line=>-9.222233105597413}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Macd.calculate(input_data, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/mfi_spec.rb b/spec/technical_analysis/indicators/mfi_spec.rb new file mode 100644 index 0000000..138b6d3 --- /dev/null +++ b/spec/technical_analysis/indicators/mfi_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "MFI" do + input_data = SpecHelper.get_test_data(:high, :low, :close, :volume) + + describe 'Money Flow Index' do + it 'Calculates MFI (14 day)' do + output = TechnicalAnalysis::Mfi.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>35.973926377719295}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>36.38768375444253}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>45.214622261116865}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>46.69168911629936}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>41.95906812943111}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78216906343063}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>35.50426811855657}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40.83081970751587}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>39.93886476277229}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>34.82129345577579}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>34.42914208336833}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>34.34229761188338}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>28.384945303826555}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>35.21136683265594}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>41.22749344358184}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>41.216526023725}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>33.960148214906965}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>26.562703378271138}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.0162422598642}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>31.547361595662196}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>31.964707056845796}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>32.76065853310956}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>34.06816082393442}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>34.05798943239071}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>41.56028762200471}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>42.20999531156955}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>43.83608665179891}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>36.043235982173}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>28.368262151706787}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>35.65846689890073}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43.77747404533765}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>49.219385053554596}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>47.94902504034211}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>48.23034273673764}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>47.447534147092476}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>39.506183778454634}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>31.23926122664477}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>29.111701049682864}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.795547568232564}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>30.54886108664553}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>37.56125308902594}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>43.66248537462054}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>50.84666407662511}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>44.40322811326429}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>36.12141791144509}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>37.81171947764313}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>44.40424662233335}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>50.1757147722236}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>50.72343663578981} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Mfi.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/mi_spec.rb b/spec/technical_analysis/indicators/mi_spec.rb new file mode 100644 index 0000000..3eb590a --- /dev/null +++ b/spec/technical_analysis/indicators/mi_spec.rb @@ -0,0 +1,46 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "MI" do + input_data = SpecHelper.get_test_data(:high, :low) + + describe 'Simple Mass Index' do + it 'Calculates MI' do + output = TechnicalAnalysis::Mi.calculate(input_data, ema_period: 9, sum_period: 25) + + expected_output = [ + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>23.82917406071097}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>23.8163614080134}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>23.890966368346767}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>23.89261610689666}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>23.835760161850434}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>23.82241708019551}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>23.792012619835983}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>23.879826345759078}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>23.94958830559542}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>24.12156756268421}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>24.303447406952383}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.454674020826847}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.564590708470064}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>24.791003528125515}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>24.964776002066408}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>25.020764664334674}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>25.03284918462693}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>25.04245599370965}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>25.018142841959207}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>25.026285600546654}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>24.924292786436485}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>24.80084030980544}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>24.77520633216394} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Mi.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/nvi_spec.rb b/spec/technical_analysis/indicators/nvi_spec.rb new file mode 100644 index 0000000..93a9de7 --- /dev/null +++ b/spec/technical_analysis/indicators/nvi_spec.rb @@ -0,0 +1,86 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "NVI" do + input_data = SpecHelper.get_test_data(:close, :volume) + + describe 'Negative Volume Index' do + it 'Calculates NVI' do + output = TechnicalAnalysis::Nvi.calculate(input_data) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>1000.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>1000.0}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>1000.0}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>1003.5719281883889}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>1001.4333482054976}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>1003.6370655407939}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>1006.0057133670583}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>1006.0057133670583}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>1004.1286907133366}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>1001.7892974768458}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>1002.8707003242093}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>1002.8707003242093}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>1001.1761721781198}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>1001.1761721781198}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>1003.6440522637729}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>1004.6386152817257}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>1002.0987352047939}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>1002.0987352047939}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>1001.8811198113682}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>1001.8811198113682}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>1001.1129093548633}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>997.0069647390503}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>997.0069647390503}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>996.4350307767862}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>996.713747493859}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>996.519622574013}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>996.519622574013}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>995.8706437612625}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>995.9218765502475}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>1001.1573361960799}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>1000.9347542454526}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>1002.8410612825647}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>1002.8410612825647} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Nvi.calculate([])}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb new file mode 100644 index 0000000..a54f3e3 --- /dev/null +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -0,0 +1,76 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "OBV Mean" do + input_data = SpecHelper.get_test_data(:close, :volume) + + describe 'On-balance Volume Mean' do + it 'Calculates OBV Mean (10 day)' do + output = TechnicalAnalysis::ObvMean.calculate(input_data, period: 10) + + expected_output = [ + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-65836555.0}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-66801824.0}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-59574127.0}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-61015077.0}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-63999351.0}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-66215087.0}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-62359854.0}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-49970286.0}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-49972807.0}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-59457699.0}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-69633236.0}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-72480397.0}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-80759219.0}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-87750647.0}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-95269809.0}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-111110335.0}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-136807276.0}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-163172458.0}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-176813851.0}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-188010709.0}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-209152907.0}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-236733893.0}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-264148349.0}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-283664797.0}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-302197756.0}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-311463969.0}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-318827806.0}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-334761235.0}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-350260027.0}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-365710262.0}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-378663120.0}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-392674222.0}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-398147027.0}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-412682868.0}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-419555627.0}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-427847140.0}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-436048331.0}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-444632138.0}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-453894366.0}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-463802236.0}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-475879438.0}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-493338562.0}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-520690509.0}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-537632267.0}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-563282378.0}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-587933850.0}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-605073347.0}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-614324095.0}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-636060876.0}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-647295525.0}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-657547495.0}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-654187384.0}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-642606913.0} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::ObvMean.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/obv_spec.rb b/spec/technical_analysis/indicators/obv_spec.rb new file mode 100644 index 0000000..088e255 --- /dev/null +++ b/spec/technical_analysis/indicators/obv_spec.rb @@ -0,0 +1,86 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "OBV" do + input_data = SpecHelper.get_test_data(:close, :volume) + + describe 'On-balance Volume' do + it 'Calculates OBV' do + output = TechnicalAnalysis::Obv.calculate(input_data) + + expected_output = [ + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-41084070}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-93986390}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-54491620}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-84772070}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-55969520}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-78662400}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-111051680}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-78177350}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-49425810}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-10744640}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-50736760}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-21709420}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-68901120}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-114614810}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-78126880}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-40110070}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>12844000}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-78202560}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-144274730}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-112500010}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-79208370}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-104497640}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-138815400}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-189806430}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-236532140}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-297079480}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-250807820}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-214616490}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-256243310}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-323921990}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-355018230}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-378642200}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-333979880}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-375136020}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-329194270}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-370717850}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-410142110}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-369604410}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-410745660}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-453450570}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-495129250}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-433370250}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-479338290}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-443863610}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-412109400}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-452729760}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-495980180}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-462226690}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-509824360}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-574222590}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-669720490}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-706889720}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-648755870}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-700364720}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-658624120}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-624124730}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-588487660}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-679594500}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-622170850}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-676742290}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-636119380}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-591085010} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Obv.calculate([])}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb new file mode 100644 index 0000000..66e18e8 --- /dev/null +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "RSI" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Relative Strength Index' do + it 'Calculates RSI (14 day)' do + output = TechnicalAnalysis::Rsi.calculate(input_data, period: 14, price_key: :close) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>38.27160493827161}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>39.38109368376431}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>44.96841382331871}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>48.08268788472883}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>37.93941116682432}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78189708111985}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>36.875893042068746}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>42.51108193242363}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>41.56699725744853}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>38.99885805229995}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>33.31877385045367}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>32.36268849740294}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>29.78632377839773}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>34.550163030510646}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>36.677863857193564}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>32.554453236286506}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>28.552282046348225}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>28.467396310763007}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>26.558433878585916}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>29.211255846774762}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>29.027101402280678}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>36.61457624117541}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>35.760430191057694}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>35.1442970032345}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>42.06016450933706}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>36.58615110748291}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>35.38441991619841}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>31.82436379692355}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>33.115551932880564}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>32.53565170863392}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>33.146531878947414}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>35.61772436774288}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>31.866930881658718}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>30.880956115136144}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>33.926041361905774}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>30.416532991054595}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>27.973957664061984}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.757134961511937}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.94077952430888}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>36.28727515078207}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>35.63166885267985}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>35.7297472286003}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>37.66054013673465}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>37.90003559360193}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>27.835833051062522}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>35.00790948034705}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>34.80538400125879}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>38.100858593859655}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>41.01572095202713} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Rsi.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index 5c8dd29..c57b417 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -1,49 +1,81 @@ require 'technical-analysis' +require 'spec_helper' describe 'Indicators' do describe "SMA" do - input_data = { - "2018-12-31": 157.74, - "2018-12-28": 156.23, - "2018-12-27": 156.15, - "2018-12-26": 157.17, - "2018-12-24": 146.83, - "2018-12-21": 150.73, - "2018-12-20": 156.83, - "2018-12-19": 160.89, - "2018-12-18": 166.07, - "2018-12-17": 163.94, - "2018-12-14": 165.48, - "2018-12-13": 170.95, - "2018-12-12": 169.1, - "2018-12-11": 168.63, - "2018-12-10": 169.6 - } + input_data = SpecHelper.get_test_data(:close) describe 'Simple Moving Average' do it 'Calculates SMA (5 day)' do - output = TechnicalAnalysis::Sma.calculate(input_data, period: 5) + output = TechnicalAnalysis::Sma.calculate(input_data, period: 5, price_key: :close) - expected_output = { - :"2018-12-14"=>168.752, - :"2018-12-17"=>167.61999999999998, - :"2018-12-18"=>167.108, - :"2018-12-19"=>165.46599999999998, - :"2018-12-20"=>162.642, - :"2018-12-21"=>159.692, - :"2018-12-24"=>156.27, - :"2018-12-26"=>154.49, - :"2018-12-27"=>153.54199999999997, - :"2018-12-28"=>153.422, - :"2018-12-31"=>154.824 - } + expected_output = [ + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>149.41}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488} + ] expect(output).to eq(expected_output) end it "Throws exception if not enough data" do - calc = Calculate.new - expect {TechnicalAnalysis::Sma.calculate(input_data, period: 30)}.to raise_exception(Validation::ValidationError) + expect {TechnicalAnalysis::Sma.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) end end end diff --git a/spec/technical_analysis/indicators/sr_spec.rb b/spec/technical_analysis/indicators/sr_spec.rb new file mode 100644 index 0000000..5451ea9 --- /dev/null +++ b/spec/technical_analysis/indicators/sr_spec.rb @@ -0,0 +1,71 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "SR" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Stochastic Oscillator' do + it 'Calculates SR (14 day)' do + output = TechnicalAnalysis::Sr.calculate(input_data, period: 14, signal_period: 3) + + expected_output = [ + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>{:sr=>39.746416758544726, :sr_signal=>32.241290132123396}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>{:sr=>70.39691289966935, :sr_signal=>46.83290323914804}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>{:sr=>88.91951488423378, :sr_signal=>66.35428151414929}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>{:sr=>10.904255319148854, :sr_signal=>56.740227701017325}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:sr=>13.123561013046874, :sr_signal=>37.649110405476506}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:sr=>21.48887183422879, :sr_signal=>15.172229388808171}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:sr=>45.203376822716805, :sr_signal=>26.605269889997487}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:sr=>39.60092095165012, :sr_signal=>35.431056536198575}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:sr=>24.174980813507332, :sr_signal=>36.326426195958085}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:sr=>1.2483574244415094, :sr_signal=>21.674753063199656}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:sr=>2.5231398354572394, :sr_signal=>9.31549269113536}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:sr=>2.388141641504267, :sr_signal=>2.0532129671343387}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:sr=>15.04254735108424, :sr_signal=>6.651276276015249}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:sr=>20.86192698325554, :sr_signal=>12.764205325281347}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:sr=>2.32807064490234, :sr_signal=>12.744181659747374}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:sr=>3.137673425827104, :sr_signal=>8.775890351328327}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:sr=>3.329837441006842, :sr_signal=>2.931860503912096}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:sr=>0.49973698053655363, :sr_signal=>2.3224159491234997}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:sr=>10.938283993978956, :sr_signal=>4.922619471840783}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:sr=>9.984947315604659, :sr_signal=>7.140989430040055}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:sr=>26.79377822378325, :sr_signal=>15.905669844455621}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:sr=>25.986013986014044, :sr_signal=>20.92157984180065}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:sr=>28.117607299763502, :sr_signal=>26.965799836520265}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:sr=>54.0861812778603, :sr_signal=>36.063267521212616}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:sr=>26.022380056253674, :sr_signal=>36.07538954462583}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:sr=>18.049737955037553, :sr_signal=>32.719433096383845}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:sr=>0.712424304917594, :sr_signal=>14.928180772069608}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:sr=>22.908293752283477, :sr_signal=>13.89015200407954}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:sr=>24.525682554372914, :sr_signal=>16.048800203857994}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:sr=>26.700601573345605, :sr_signal=>24.711525960000667}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:sr=>35.26145303100408, :sr_signal=>28.8292457195742}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:sr=>9.94909763998139, :sr_signal=>23.970384081443694}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:sr=>5.447996398018944, :sr_signal=>16.886182356334803}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:sr=>15.038271049077, :sr_signal=>10.145121695692445}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:sr=>6.963249516440942, :sr_signal=>9.149838987845628}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:sr=>5.161943319838063, :sr_signal=>9.054487961785336}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:sr=>3.1152647975077716, :sr_signal=>5.080152544595593}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:sr=>0.6703929340585003, :sr_signal=>2.9825336838014445}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:sr=>37.531039375665074, :sr_signal=>13.772232369077116}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:sr=>34.2652329749104, :sr_signal=>24.155555094877986}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:sr=>37.105465742879105, :sr_signal=>36.300579364484854}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:sr=>42.917628945342614, :sr_signal=>38.09610922104404}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:sr=>43.61046959199379, :sr_signal=>41.21118809340517}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:sr=>0.6215243702976702, :sr_signal=>29.04987430254469}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:sr=>23.1166912850812, :sr_signal=>22.449561749124218}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:sr=>22.50474383301711, :sr_signal=>15.414319829465327}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:sr=>34.27340383862123, :sr_signal=>26.631612985573174}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:sr=>44.44007858546172, :sr_signal=>33.739408752366685}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Sr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/trix_spec.rb b/spec/technical_analysis/indicators/trix_spec.rb new file mode 100644 index 0000000..e6220e1 --- /dev/null +++ b/spec/technical_analysis/indicators/trix_spec.rb @@ -0,0 +1,43 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "TRIX" do + input_data = SpecHelper.get_test_data(:close) + + describe 'Triple Exponential Average' do + it 'Calculates TRIX (15 day)' do + output = TechnicalAnalysis::Trix.calculate(input_data, period: 15, price_key: :close) + + expected_output = [ + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.007673381215454718}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.007622995995719011}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.007537530463588133}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.007473061875390961}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.007428539823046746}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.007365504921638632}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.007332615495168546}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.00735126292321306}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.007455715388896471}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.007643867247128558}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.00776162437514068}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.007824502562605692}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.007833433859114468}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.007775594696883065}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.007658933006361239}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.007665196848424279}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.00767662212545961}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.007682172922749195}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.007639218329257057}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.007522826289174942} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Trix.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/tsi_spec.rb b/spec/technical_analysis/indicators/tsi_spec.rb new file mode 100644 index 0000000..bef3452 --- /dev/null +++ b/spec/technical_analysis/indicators/tsi_spec.rb @@ -0,0 +1,54 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "TSI" do + input_data = SpecHelper.get_test_data(:close) + + describe 'True Strength Index' do + it 'Calculates True Strength Index' do + output = TechnicalAnalysis::Tsi.calculate(input_data, low_period: 13, high_period: 25, price_key: :close) + + expected_output = [ + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-32.212798598181024}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-29.524570107700253}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28.752945178257534}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-28.4796578607378}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-29.357900955250976}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.704744795960114}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-30.15935663446155}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-30.375476807689427}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-29.91401235092671}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-30.569488217596724}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-31.403055885745307}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-31.30170501401141}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-32.23640227177938}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-33.78946079860395}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-36.202827241203856}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-38.83883734905748}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-36.802531445786066}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-35.41195667338275}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-34.28080772951784}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-32.785927300024994}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-31.495178028566524}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-33.579027007940994}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-32.874679857827935}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-32.39480993311267}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-30.97413963420104}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-28.91017661103889} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + low_period = 13 + high_period = 25 + size_limit = low_period + high_period - 1 + input_data = input_data.first(size_limit) + + expect {TechnicalAnalysis::Tsi.calculate(input_data, low_period: low_period, high_period: high_period, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/uo_spec.rb b/spec/technical_analysis/indicators/uo_spec.rb new file mode 100644 index 0000000..ebe644d --- /dev/null +++ b/spec/technical_analysis/indicators/uo_spec.rb @@ -0,0 +1,58 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "UO" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Ultimate Oscillator' do + it 'Calculates UO (5 day)' do + output = TechnicalAnalysis::Uo.calculate(input_data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) + + expected_output = [ + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>37.48593642184523}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>33.50557345611348}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>29.938582222468735}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>30.12209085444982}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.31628731487427}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>37.129780535443615}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>36.448196445521205}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>39.6100967511459}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>42.75825214517756}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>48.76091038333585}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>58.63742128493122}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>54.53131218526129}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>54.531561679403225}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>46.3795568325064}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>46.78620949538559}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>47.39018769748099}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>46.56343334880161}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>42.5926187322538}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43.99139965247388}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>38.091246151228205}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>42.6017793901735}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>31.693410049073588}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>30.219780692869403}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>28.31825074884628}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.01487703769969}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>38.89197235556109}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>44.80062908207362}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>44.736408028234784}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46.12625788315007}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>51.63477005783912}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>43.660461129633255}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>50.726610056055335}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>46.58165158841807}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>44.828908983561035}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>47.28872762629681} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Uo.calculate(input_data, long_period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/vi_spec.rb b/spec/technical_analysis/indicators/vi_spec.rb new file mode 100644 index 0000000..5b456cc --- /dev/null +++ b/spec/technical_analysis/indicators/vi_spec.rb @@ -0,0 +1,72 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "VI" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Vortex Indicator' do + it 'Calculates VI (14 day)' do + output = TechnicalAnalysis::Vi.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:negative_vi=>0.9987535631315481, :positive_vi=>0.7711714493088508}}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:negative_vi=>1.0400453579079016, :positive_vi=>0.8594387814137219}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:negative_vi=>0.9136449963918103, :positive_vi=>0.9374983015842824}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:negative_vi=>0.9510765744895432, :positive_vi=>0.9155241699342749}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:negative_vi=>0.9506581829483907, :positive_vi=>0.7977446639361122}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:negative_vi=>1.017756255044391, :positive_vi=>0.73372163931486}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:negative_vi=>1.0107777977366625, :positive_vi=>0.7408837794144069}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:negative_vi=>0.9456323099415208, :positive_vi=>0.8265716374269011}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:negative_vi=>0.9713674816398625, :positive_vi=>0.8198382448638102}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:negative_vi=>1.0059420422342082, :positive_vi=>0.7587530852911607}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:negative_vi=>1.0186513629842182, :positive_vi=>0.7271341463414641}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:negative_vi=>1.053272641569953, :positive_vi=>0.6968210271671884}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:negative_vi=>1.0659261208578774, :positive_vi=>0.6477869675714517}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:negative_vi=>1.0787197159390678, :positive_vi=>0.6861446786495575}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:negative_vi=>1.0499147710692558, :positive_vi=>0.7525644147579889}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:negative_vi=>1.018527704309603, :positive_vi=>0.6562081533662589}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:negative_vi=>1.1182403853648055, :positive_vi=>0.5634420498548615}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:negative_vi=>1.1504168141815485, :positive_vi=>0.5639363354788292}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:negative_vi=>1.2070792620527797, :positive_vi=>0.6046320015251558}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:negative_vi=>1.1658984366885399, :positive_vi=>0.65775873808705}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:negative_vi=>1.1714346511931206, :positive_vi=>0.6287012609627801}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:negative_vi=>1.1564601777941095, :positive_vi=>0.6464192792510783}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:negative_vi=>1.1373201600900555, :positive_vi=>0.6548920237509929}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:negative_vi=>1.1516224812958684, :positive_vi=>0.6987674707967169}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:negative_vi=>1.0746012192731307, :positive_vi=>0.8019709726837323}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:negative_vi=>1.0423007389465182, :positive_vi=>0.7496451535522679}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:negative_vi=>1.0795256042654737, :positive_vi=>0.7516804020221332}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:negative_vi=>1.050514334444714, :positive_vi=>0.7172185077490695}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:negative_vi=>1.136139122315593, :positive_vi=>0.6334605508870221}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:negative_vi=>1.1040510191627, :positive_vi=>0.7505785426583675}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:negative_vi=>1.0422719380259118, :positive_vi=>0.8400547615867511}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:negative_vi=>1.011590726346824, :positive_vi=>0.8266537121415173}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:negative_vi=>0.9867067848168232, :positive_vi=>0.8214508662875287}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:negative_vi=>0.974913770577476, :positive_vi=>0.814344133786256}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:negative_vi=>0.9773071878279123, :positive_vi=>0.8213523084994758}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:negative_vi=>1.067568020631851, :positive_vi=>0.7127001934235981}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:negative_vi=>1.1525346959374216, :positive_vi=>0.6361329800656076}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:negative_vi=>1.1606095395904847, :positive_vi=>0.5994780447390226}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:negative_vi=>1.3088205560235893, :positive_vi=>0.5374882657359492}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:negative_vi=>1.2335085243974138, :positive_vi=>0.636331569664903}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:negative_vi=>1.1655798789007923, :positive_vi=>0.729855612482534}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:negative_vi=>1.1487474529545731, :positive_vi=>0.8037876063766033}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:negative_vi=>1.08671679197995, :positive_vi=>0.8781954887218045}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:negative_vi=>1.1146552806731134, :positive_vi=>0.8035916112018086}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:negative_vi=>1.114675915889877, :positive_vi=>0.7324951224799482}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:negative_vi=>1.0760915145470467, :positive_vi=>0.7417758715458455}}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:negative_vi=>1.0577860164333046, :positive_vi=>0.813115261460082}}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:negative_vi=>1.0113586362578701, :positive_vi=>0.8600571901821686}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Vi.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/vpt_spec.rb b/spec/technical_analysis/indicators/vpt_spec.rb new file mode 100644 index 0000000..f0a56ba --- /dev/null +++ b/spec/technical_analysis/indicators/vpt_spec.rb @@ -0,0 +1,85 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "VPT" do + input_data = SpecHelper.get_test_data(:close, :volume) + + describe 'Volume-Price Trend' do + it 'Calculates VPT' do + output = TechnicalAnalysis::Vpt.calculate(input_data) + + expected_output = [ + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-1903264.3174505206}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-2370279.621573285}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-959554.7990039173}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-1607126.441433344}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-972399.6540759658}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-1070464.7668376141}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-1827517.8777377433}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-1326839.4882367724}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-1151165.4943468445}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-786529.9466468699}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-2158324.481734193}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-1522689.2992524402}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-2274149.490335243}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-3132205.8074873467}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-2949972.4593908517}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-1959004.510023763}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-1146038.8004377298}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-7185217.517024899}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-9060892.67270255}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-8717279.945880784}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-7707600.723227796}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-7883463.234301859}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-8545161.134440955}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-11113790.317206156}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-11580638.32359231}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-13290943.979317216}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-12149014.896876106}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-11748170.533467716}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-13397928.75906581}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-16631473.78435367}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-16666614.749434467}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-17266635.256844807}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-16662634.99217477}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-16752197.088154612}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-14985612.348714761}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-15304600.832189944}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-15517586.252407152}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-14101104.854714246}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-15910856.843135413}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-16386993.991247926}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-17873132.82137613}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-17466268.97188952}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-17729175.804436687}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-17630301.940948576}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-17282902.245502096}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-18582658.71932485}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18985158.397835847}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18546614.21276814}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-20031264.8456338}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-21656330.504158247}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-25370780.481841102}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-26332500.093066465}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22238622.758734256}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22573553.26073845}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-22552168.387219403}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-22218723.601326805}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-22178057.48873647}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31252972.592586517}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-28801593.76496151}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-28923059.940598898}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-28148662.548589166}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-27383899.78109331} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Vpt.calculate([])}.to raise_exception(Validation::ValidationError) + end + end + end +end diff --git a/spec/technical_analysis/indicators/wr_spec.rb b/spec/technical_analysis/indicators/wr_spec.rb new file mode 100644 index 0000000..49e2d88 --- /dev/null +++ b/spec/technical_analysis/indicators/wr_spec.rb @@ -0,0 +1,73 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "WR" do + input_data = SpecHelper.get_test_data(:high, :low, :close) + + describe 'Williams %R' do + it 'Calculates Williams %R' do + output = TechnicalAnalysis::Wr.calculate(input_data, period: 14) + + expected_output = [ + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-73.3779264214046}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-69.64461994076994}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-60.253583241455274}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-29.60308710033065}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-11.080485115766221}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-89.09574468085114}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-86.87643898695312}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-78.51112816577121}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-54.79662317728319}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-60.39907904834988}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-75.82501918649267}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-98.75164257555849}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-97.47686016454276}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-97.61185835849572}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-84.95745264891575}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-79.13807301674446}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-97.67192935509766}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-96.8623265741729}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-96.67016255899316}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-99.50026301946345}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-89.06171600602104}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-90.01505268439534}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-73.20622177621675}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-74.01398601398596}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-71.8823927002365}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-45.9138187221397}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-73.97761994374633}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-81.95026204496244}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-99.28757569508241}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-77.09170624771653}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-75.47431744562708}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-73.29939842665439}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-64.73854696899592}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-90.0509023600186}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-94.55200360198106}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-84.961728950923}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-93.03675048355906}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-94.83805668016194}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-96.88473520249222}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-99.32960706594149}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-62.468960624334926}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-65.7347670250896}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-62.8945342571209}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-57.082371054657386}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-56.38953040800621}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-99.37847562970234}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-76.88330871491881}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-77.4952561669829}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-65.72659616137877}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-55.55992141453828} + ] + + expect(output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {TechnicalAnalysis::Wr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + end + end +end From 183df230a55d005d81882b9bb66f2c95f54374d1 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 15:01:34 -0500 Subject: [PATCH 02/84] Create Indicator class - Used to calculate and find data across all indicators - Used for inheritance by each indicator - Add to require --- lib/technical_analysis.rb | 2 + .../indicators/indicator.rb | 90 +++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 lib/technical_analysis/indicators/indicator.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index 15274cf..4205c65 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -4,6 +4,8 @@ require 'technical_analysis/helpers/validation' # Indicators +require 'technical_analysis/indicators/indicator' + require 'technical_analysis/indicators/adi' require 'technical_analysis/indicators/adtv' require 'technical_analysis/indicators/adx' diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb new file mode 100644 index 0000000..039a66b --- /dev/null +++ b/lib/technical_analysis/indicators/indicator.rb @@ -0,0 +1,90 @@ +module TechnicalAnalysis + class Indicator + + CALCULATIONS = [ + :min_data_size, + :technicals, + ].freeze + + def self.symbol + raise "#{self.name} did not implement symbol" + end + + def self.roster + [ + TechnicalAnalysis::Adi, + TechnicalAnalysis::Adtv, + TechnicalAnalysis::Adx, + TechnicalAnalysis::Ao, + TechnicalAnalysis::Atr, + TechnicalAnalysis::Bb, + TechnicalAnalysis::Cci, + TechnicalAnalysis::Cmf, + TechnicalAnalysis::Cr, + TechnicalAnalysis::Dc, + TechnicalAnalysis::Dlr, + TechnicalAnalysis::Dpo, + TechnicalAnalysis::Dr, + TechnicalAnalysis::Eom, + TechnicalAnalysis::Evm, + TechnicalAnalysis::Fi, + TechnicalAnalysis::Ichimoku, + TechnicalAnalysis::Kc, + TechnicalAnalysis::Kst, + TechnicalAnalysis::Macd, + TechnicalAnalysis::Mfi, + TechnicalAnalysis::Mi, + TechnicalAnalysis::Nvi, + TechnicalAnalysis::Obv, + TechnicalAnalysis::ObvMean, + TechnicalAnalysis::Rsi, + TechnicalAnalysis::Sma, + TechnicalAnalysis::Sr, + TechnicalAnalysis::Trix, + TechnicalAnalysis::Tsi, + TechnicalAnalysis::Uo, + TechnicalAnalysis::Vi, + TechnicalAnalysis::Vpt, + TechnicalAnalysis::Wr, + ] + end + + # Finds the applicable indicator and returns an instance + def self.find(indicator_symbol) + self.roster.each do |indicator| + return indicator if indicator.symbol == indicator_symbol + end + + nil + end + + # Find the applicable indicator and looks up the value + def self.calculate(indicator_symbol, data, calculation, options={}) + return nil unless CALCULATIONS.include? calculation + + indicator = find(indicator_symbol) + raise "Indicator not found!" if indicator.nil? + + indicator.validate_options(options) + + case calculation + when :technicals; librarian.calculate(data, options) + when :min_data_size; librarian.min_data_size(options) + else nil + end + end + + # Calculates the minimum data size for an indicator + def self.min_data_size(indicator_symbol, options) + raise "#{self.name} did not implement min_data_size" + nil + end + + # Validates the options for the indicator + def self.validate_options(options) + raise "#{self.name} did not implement validate_options" + false + end + + end +end From 477e5916ab7a8f9b97d404142ca250717dc8e475 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 15:02:26 -0500 Subject: [PATCH 03/84] Add Indicator inheritance and symbol methods - Inherit from Indicator class - Add symbol method - Fix empty spaces --- lib/technical_analysis/indicators/adi.rb | 8 +++++-- lib/technical_analysis/indicators/adtv.rb | 8 +++++-- lib/technical_analysis/indicators/adx.rb | 8 +++++-- lib/technical_analysis/indicators/ao.rb | 8 +++++-- lib/technical_analysis/indicators/atr.rb | 8 +++++-- lib/technical_analysis/indicators/bb.rb | 8 +++++-- lib/technical_analysis/indicators/cci.rb | 8 +++++-- lib/technical_analysis/indicators/cmf.rb | 8 +++++-- lib/technical_analysis/indicators/cr.rb | 8 +++++-- lib/technical_analysis/indicators/dc.rb | 8 +++++-- lib/technical_analysis/indicators/dlr.rb | 8 +++++-- lib/technical_analysis/indicators/dpo.rb | 8 +++++-- lib/technical_analysis/indicators/dr.rb | 8 +++++-- lib/technical_analysis/indicators/eom.rb | 8 +++++-- lib/technical_analysis/indicators/evm.rb | 4 ++++ lib/technical_analysis/indicators/fi.rb | 8 +++++-- lib/technical_analysis/indicators/ichimoku.rb | 8 +++++-- lib/technical_analysis/indicators/kc.rb | 8 +++++-- lib/technical_analysis/indicators/kst.rb | 8 +++++-- lib/technical_analysis/indicators/macd.rb | 8 +++++-- lib/technical_analysis/indicators/mfi.rb | 8 +++++-- lib/technical_analysis/indicators/mi.rb | 8 +++++-- lib/technical_analysis/indicators/nvi.rb | 8 +++++-- lib/technical_analysis/indicators/obv.rb | 8 +++++-- lib/technical_analysis/indicators/obv_mean.rb | 8 +++++-- lib/technical_analysis/indicators/rsi.rb | 8 +++++-- lib/technical_analysis/indicators/sma.rb | 21 +++++++++++++++---- lib/technical_analysis/indicators/sr.rb | 8 +++++-- lib/technical_analysis/indicators/trix.rb | 8 +++++-- lib/technical_analysis/indicators/tsi.rb | 8 +++++-- lib/technical_analysis/indicators/uo.rb | 8 +++++-- lib/technical_analysis/indicators/vi.rb | 8 +++++-- lib/technical_analysis/indicators/vpt.rb | 8 +++++-- lib/technical_analysis/indicators/wr.rb | 8 +++++-- 34 files changed, 213 insertions(+), 68 deletions(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index ddf76aa..faac82b 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Adi + class Adi < Indicator + + def self.symbol + "adi" + end # Calculates the Accumulation/Distribution Index for the given data # https://en.wikipedia.org/wiki/Accumulation/distribution_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index c616477..72125e1 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Adtv + class Adtv < Indicator + + def self.symbol + "adtv" + end # Calculates the average daily trading volume (ADTV) for the data over the given period # https://www.investopedia.com/terms/a/averagedailytradingvolume.asp - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given number of days used to calculate the ADTV # @param volume_key [Symbol] The hash key for the volume data. Default :value diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index b36ae45..bcb9b8d 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Adx + class Adx < Indicator + + def self.symbol + "adx" + end # Calculates the average directional index (ADX) for the data over the given period # https://en.wikipedia.org/wiki/Average_directional_movement_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the ADX # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 1ae788a..7692051 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Ao + class Ao < Indicator + + def self.symbol + "ao" + end # Calculates the Awesome Oscillator for the data over the given period # https://www.tradingview.com/wiki/Awesome_Oscillator_(AO) - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low) # @param short_period [Integer] The given period to calculate the short period SMA # @param long_period [Integer] The given period to calculate the long period SMA diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index bfe5e5b..0d601ea 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Atr + class Atr < Indicator + + def self.symbol + "atr" + end # Calculates the average true range (ATR) for the data over the given period # https://en.wikipedia.org/wiki/Average_true_range - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the ATR # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index ef11306..eb6dbe3 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Bb + class Bb < Indicator + + def self.symbol + "bb" + end # Calculates the bollinger bands (BB) for the data over the given period # https://en.wikipedia.org/wiki/Bollinger_Bands - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the BB # @param standard_deviations [Integer] The given standard deviations to calculate the upper and lower bands of the BB diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 066dde2..ab97405 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Cci + class Cci < Indicator + + def self.symbol + "cci" + end # Calculates the commodity channel index for the data over the given period # https://en.wikipedia.org/wiki/Commodity_channel_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the CCI # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of CCI values would fall between −100 and +100 diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index b660036..bc3aaa4 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Cmf + class Cmf < Indicator + + def self.symbol + "cmf" + end # Calculates the chaikin money flow (CMF) for the data over the given period # https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:chaikin_money_flow_cmf - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the CMF # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 3f504ab..7f1862e 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Cr + class Cr < Indicator + + def self.symbol + "cr" + end # Calculates the cumulative return for the data over the given period # https://www.investopedia.com/terms/c/cumulativereturn.asp - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index da83e44..33050a8 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Dc + class Dc < Indicator + + def self.symbol + "dc" + end # Calculates the donchian channel (DC) for the data over the given period # https://en.wikipedia.org/wiki/Donchian_channel - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the DC # @param price_key [Symbol] The hash key for the price data. Default :value diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index c1f0d54..90f4d48 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis - class Dlr + class Dlr < Indicator + + def self.symbol + "dlr" + end # Calculates the daily log return (percent expressed as a decimal) for the data over the given period # https://www.quora.com/What-are-daily-log-returns-of-an-equity # https://en.wikipedia.org/wiki/Rate_of_return#Logarithmic_or_continuously_compounded_return - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 71b65d2..0793be7 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Dpo + class Dpo < Indicator + + def self.symbol + "dpo" + end # Calculates the detrended price oscillator for the data over the given period # https://en.wikipedia.org/wiki/Detrended_price_oscillator - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index f192057..26c19d4 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Dr + class Dr < Indicator + + def self.symbol + "dr" + end # Calculates the daily return (percent expressed as a decimal) for the data over the given period # https://en.wikipedia.org/wiki/Rate_of_return - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index c2719e9..1d0e7f2 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Eom + class Eom < Indicator + + def self.symbol + "eom" + end # Calculates the ease of movement (EoM and EVM) for the data over the given period # https://en.wikipedia.org/wiki/Ease_of_movement - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) # @param period [Integer] The given period to calculate the Eom / EVM # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index ef46092..b334394 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -1,3 +1,7 @@ module TechnicalAnalysis Evm = Eom + + def self.symbol + "evm" + end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 3d656f2..8fd30ca 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Fi + class Fi < Indicator + + def self.symbol + "fi" + end # Calculates the force index (FI) for the data # https://en.wikipedia.org/wiki/Force_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index a4788b5..2e0cd72 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -1,5 +1,9 @@ module TechnicalAnalysis - class Ichimoku + class Ichimoku < Indicator + + def self.symbol + "ichimoku" + end # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimooku) for the data over the given period # 1. tenkan_sen (Conversion Line) @@ -8,7 +12,7 @@ class Ichimoku # 4. senkou_span_b (Leading Span B) # 5. chickou_span (Lagging Span) # https://en.wikipedia.org/wiki/Ichimoku_Kink%C5%8D_Hy%C5%8D - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param low_period [Integer] The given period to calculate tenkan_sen (Conversion Line) # @param medium_period [Integer] The given period to calculate kijun_sen (Base Line), senkou_span_a (Leading Span A), and chikou_span (Lagging Span) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 242f0fe..8e9b9b2 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Kc + class Kc < Indicator + + def self.symbol + "kc" + end # Calculates the keltner channel (KC) for the data over the given period # https://en.wikipedia.org/wiki/Keltner_channel - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the KC # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 2b2180b..7bab99b 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Kst + class Kst < Indicator + + def self.symbol + "kst" + end # Calculates the know sure thing for the data over the given period # https://en.wikipedia.org/wiki/KST_oscillator - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param roc1 [Integer] The given period to calculate the rate-of-change for RCMA1 # @param roc2 [Integer] The given period to calculate the rate-of-change for RCMA2 diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index a7d5afc..d7e0cf0 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Macd + class Macd < Indicator + + def self.symbol + "macd" + end # Calculates the moving average convergence divergence (MACD) for the data over the given period # https://en.wikipedia.org/wiki/MACD - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param fast_period [Integer] The given period to calculate the fast moving EMA for MACD # @param slow_period [Integer] The given period to calculate the slow moving EMA for MACD diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 3743291..a2457e7 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Mfi + class Mfi < Indicator + + def self.symbol + "mfi" + end # Calculates the money flow index (MFI) for the data over the given period # https://en.wikipedia.org/wiki/Money_flow_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the MFI # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index ba7872a..fecc3a7 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Mi + class Mi < Indicator + + def self.symbol + "mi" + end # Calculates the mass index (MI) for the data over the given period # https://en.wikipedia.org/wiki/Mass_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low) # @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA # @param period [Integer] The given period to calculate the MI diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 1fd4c43..2d461b4 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Nvi + class Nvi < Indicator + + def self.symbol + "nvi" + end # Calculates the negative volume index (NVI) for the data # https://en.wikipedia.org/wiki/Negative_volume_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data) diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index c516073..129b98d 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Obv + class Obv < Indicator + + def self.symbol + "obv" + end # Calculates the on-balance volume (OBV) for the data over the given period # https://en.wikipedia.org/wiki/On-balance_volume - # + # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data) diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 910b56e..d09524e 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class ObvMean + class ObvMean < Indicator + + def self.symbol + "obv_mean" + end # Calculates the on-balance volume mean (OBV mean) for the data over the given period # https://en.wikipedia.org/wiki/On-balance_volume - # + # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @param period [Integer] The given period to calculate the OBV mean # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 2c72a53..951f533 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Rsi + class Rsi < Indicator + + def self.symbol + "rsi" + end # Calculates the relative strength index for the data over the given period # https://en.wikipedia.org/wiki/Relative_strength_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the RSI # @param price_key [Symbol] The hash key for the price data. Default :value diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index a79f827..4a485d7 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -1,9 +1,22 @@ module TechnicalAnalysis - class Sma + class Sma < Indicator + + def self.symbol + "sma" + end + + def self.min_data_size(options) + options[:period] + end + + def self.validate_options(options) + return true if (options.keys - [:period, :price_key]).empty? + raise "Invalid options!" + end # Calculates the simple moving average for the data over the given period # https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value @@ -11,7 +24,7 @@ class Sma def self.calculate(data, period: 30, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) - + data = data.sort_by_hash_date_time_asc output = [] @@ -25,7 +38,7 @@ def self.calculate(data, period: 30, price_key: :value) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 798cc3b..233ca7f 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Sr + class Sr < Indicator + + def self.symbol + "sr" + end # Calculates the stochastic oscillator (%K) for the data over the given period # https://en.wikipedia.org/wiki/Stochastic_oscillator - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the SR # @return [Array] Array of hashes with keys(:date_time, :value) diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 04b2c29..5fcfb67 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Trix + class Trix < Indicator + + def self.symbol + "trix" + end # Calculates the triple exponential average (Trix) for the data over the given period # https://en.wikipedia.org/wiki/Trix_(technical_analysis) - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the EMA for Trix # @param price_key [Symbol] The hash key for the price data. Default :value diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index ea4ea07..a39dc37 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Tsi + class Tsi < Indicator + + def self.symbol + "tsi" + end # Calculates the true strenth index for the data over the given period # https://en.wikipedia.org/wiki/True_strength_index - # + # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param high_period [Integer] The given high period to calculate the EMA # @param low_period [Integer] The given low period to calculate the EMA diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index eb2c927..c1b1541 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Uo + class Uo < Indicator + + def self.symbol + "uo" + end # Calculates the ultimate oscillator for the data over the given period # https://en.wikipedia.org/wiki/Ultimate_oscillator - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param short_period [Integer] The given short period # @param medium_period [Integer] The given medium period diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 8b102e1..2f99431 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Vi + class Vi < Indicator + + def self.symbol + "vi" + end # Calculates the vortex indicatorfor the data over the given period # https://en.wikipedia.org/wiki/Vortex_indicator - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the VI # @return [Hash] A hash of the results with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index 096098b..3a4491c 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Vpt + class Vpt < Indicator + + def self.symbol + "vpt" + end # Calculates the volume-price trend (VPT) for the data # https://en.wikipedia.org/wiki/Volume%E2%80%93price_trend - # + # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data) diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index eb521c1..e807fa9 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -1,9 +1,13 @@ module TechnicalAnalysis - class Wr + class Wr < Indicator + + def self.symbol + "wr" + end # Calculates the Williams %R for the data over the given period # https://en.wikipedia.org/wiki/Williams_%25R - # + # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given look-back period to calculate the Williams %R # @return [Hash] A hash of the results with keys (:date_time, :value) From 787f91a27d0c2f41bcb5ebd5609a6b7a4118499f Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 15:12:11 -0500 Subject: [PATCH 04/84] Change old librarian reference to indicator --- lib/technical_analysis/indicators/indicator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 039a66b..eb19811 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -68,8 +68,8 @@ def self.calculate(indicator_symbol, data, calculation, options={}) indicator.validate_options(options) case calculation - when :technicals; librarian.calculate(data, options) - when :min_data_size; librarian.min_data_size(options) + when :technicals; indicator.calculate(data, options) + when :min_data_size; indicator.min_data_size(options) else nil end end From 194f4d25b7ceb4b251eeb0b7602ff155e2c826e0 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 17:00:18 -0500 Subject: [PATCH 05/84] Add min_data_size method to each indicator --- lib/technical_analysis/indicators/adi.rb | 4 ++++ lib/technical_analysis/indicators/adtv.rb | 4 ++++ lib/technical_analysis/indicators/adx.rb | 4 ++++ lib/technical_analysis/indicators/ao.rb | 4 ++++ lib/technical_analysis/indicators/atr.rb | 4 ++++ lib/technical_analysis/indicators/bb.rb | 4 ++++ lib/technical_analysis/indicators/cci.rb | 4 ++++ lib/technical_analysis/indicators/cmf.rb | 4 ++++ lib/technical_analysis/indicators/cr.rb | 4 ++++ lib/technical_analysis/indicators/dc.rb | 4 ++++ lib/technical_analysis/indicators/dlr.rb | 4 ++++ lib/technical_analysis/indicators/dpo.rb | 4 ++++ lib/technical_analysis/indicators/dr.rb | 4 ++++ lib/technical_analysis/indicators/eom.rb | 4 ++++ lib/technical_analysis/indicators/fi.rb | 4 ++++ lib/technical_analysis/indicators/ichimoku.rb | 4 ++++ lib/technical_analysis/indicators/kc.rb | 4 ++++ lib/technical_analysis/indicators/kst.rb | 4 ++++ lib/technical_analysis/indicators/macd.rb | 4 ++++ lib/technical_analysis/indicators/mfi.rb | 4 ++++ lib/technical_analysis/indicators/mi.rb | 4 ++++ lib/technical_analysis/indicators/nvi.rb | 4 ++++ lib/technical_analysis/indicators/obv.rb | 4 ++++ lib/technical_analysis/indicators/obv_mean.rb | 4 ++++ lib/technical_analysis/indicators/rsi.rb | 4 ++++ lib/technical_analysis/indicators/sma.rb | 4 ++-- lib/technical_analysis/indicators/sr.rb | 4 ++++ lib/technical_analysis/indicators/trix.rb | 4 ++++ lib/technical_analysis/indicators/tsi.rb | 4 ++++ lib/technical_analysis/indicators/uo.rb | 4 ++++ lib/technical_analysis/indicators/vi.rb | 4 ++++ lib/technical_analysis/indicators/vpt.rb | 4 ++++ lib/technical_analysis/indicators/wr.rb | 4 ++++ 33 files changed, 130 insertions(+), 2 deletions(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index faac82b..6918e37 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -5,6 +5,10 @@ def self.symbol "adi" end + def self.min_data_size(**params) + 1 + end + # Calculates the Accumulation/Distribution Index for the given data # https://en.wikipedia.org/wiki/Accumulation/distribution_index # diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 72125e1..828e7ba 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -5,6 +5,10 @@ def self.symbol "adtv" end + def self.min_data_size(period: 22, **params) + period + end + # Calculates the average daily trading volume (ADTV) for the data over the given period # https://www.investopedia.com/terms/a/averagedailytradingvolume.asp # diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index bcb9b8d..4fcfcc2 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -5,6 +5,10 @@ def self.symbol "adx" end + def self.min_data_size(period: 14) + period * 2 + end + # Calculates the average directional index (ADX) for the data over the given period # https://en.wikipedia.org/wiki/Average_directional_movement_index # diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 7692051..17924d0 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -5,6 +5,10 @@ def self.symbol "ao" end + def self.min_data_size(long_period: 34, **params) + long_period + end + # Calculates the Awesome Oscillator for the data over the given period # https://www.tradingview.com/wiki/Awesome_Oscillator_(AO) # diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 0d601ea..8e07773 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -5,6 +5,10 @@ def self.symbol "atr" end + def self.min_data_size(period: 14) + period + 1 + end + # Calculates the average true range (ATR) for the data over the given period # https://en.wikipedia.org/wiki/Average_true_range # diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index eb6dbe3..08176b0 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -5,6 +5,10 @@ def self.symbol "bb" end + def self.min_data_size(period: 20, **params) + period + end + # Calculates the bollinger bands (BB) for the data over the given period # https://en.wikipedia.org/wiki/Bollinger_Bands # diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index ab97405..c597f0d 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -5,6 +5,10 @@ def self.symbol "cci" end + def self.min_data_size(period: 20, **params) + period + end + # Calculates the commodity channel index for the data over the given period # https://en.wikipedia.org/wiki/Commodity_channel_index # diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index bc3aaa4..b68ffba 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -5,6 +5,10 @@ def self.symbol "cmf" end + def self.min_data_size(period: 20) + period + end + # Calculates the chaikin money flow (CMF) for the data over the given period # https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:chaikin_money_flow_cmf # diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 7f1862e..703c955 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -5,6 +5,10 @@ def self.symbol "cr" end + def min_data_size(**params) + 1 + end + # Calculates the cumulative return for the data over the given period # https://www.investopedia.com/terms/c/cumulativereturn.asp # diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 33050a8..18c4816 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -5,6 +5,10 @@ def self.symbol "dc" end + def self.min_data_size(period: 20, **params) + period + end + # Calculates the donchian channel (DC) for the data over the given period # https://en.wikipedia.org/wiki/Donchian_channel # diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 90f4d48..c7ea36c 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -5,6 +5,10 @@ def self.symbol "dlr" end + def self.min_data_size(**params) + 1 + end + # Calculates the daily log return (percent expressed as a decimal) for the data over the given period # https://www.quora.com/What-are-daily-log-returns-of-an-equity # https://en.wikipedia.org/wiki/Rate_of_return#Logarithmic_or_continuously_compounded_return diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 0793be7..e3f2025 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -5,6 +5,10 @@ def self.symbol "dpo" end + def self.min_data_size(period: 20, **params) + period + (period / 2) + end + # Calculates the detrended price oscillator for the data over the given period # https://en.wikipedia.org/wiki/Detrended_price_oscillator # diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 26c19d4..7c0cf43 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -5,6 +5,10 @@ def self.symbol "dr" end + def self.min_data_size(**params) + 1 + end + # Calculates the daily return (percent expressed as a decimal) for the data over the given period # https://en.wikipedia.org/wiki/Rate_of_return # diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 1d0e7f2..400dada 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -5,6 +5,10 @@ def self.symbol "eom" end + def self.min_data_size(period: 14) + period + 1 + end + # Calculates the ease of movement (EoM and EVM) for the data over the given period # https://en.wikipedia.org/wiki/Ease_of_movement # diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 8fd30ca..9b534d2 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -5,6 +5,10 @@ def self.symbol "fi" end + def self.min_data_size(**params) + 2 + end + # Calculates the force index (FI) for the data # https://en.wikipedia.org/wiki/Force_index # diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 2e0cd72..cae5e63 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -5,6 +5,10 @@ def self.symbol "ichimoku" end + def self.min_data_size(medium_period: 26, high_period: 52, **params) + high_period + medium_period - 2 + end + # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimooku) for the data over the given period # 1. tenkan_sen (Conversion Line) # 2. kijun_sen (Base Line) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 8e9b9b2..aa6150d 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -5,6 +5,10 @@ def self.symbol "kc" end + def self.min_data_size(period: 10) + period + end + # Calculates the keltner channel (KC) for the data over the given period # https://en.wikipedia.org/wiki/Keltner_channel # diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 7bab99b..a0e08d6 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -5,6 +5,10 @@ def self.symbol "kst" end + def self.min_data_size(roc4: 30, sma4: 15, **params) + roc4 + sma4 - 1 + end + # Calculates the know sure thing for the data over the given period # https://en.wikipedia.org/wiki/KST_oscillator # diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index d7e0cf0..d7c9aad 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -5,6 +5,10 @@ def self.symbol "macd" end + def self.min_data_size(slow_period: 26, signal_period: 9, **params) + slow_period + signal_period + end + # Calculates the moving average convergence divergence (MACD) for the data over the given period # https://en.wikipedia.org/wiki/MACD # diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index a2457e7..028d878 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -5,6 +5,10 @@ def self.symbol "mfi" end + def self.min_data_size(period: 14) + period + 1 + end + # Calculates the money flow index (MFI) for the data over the given period # https://en.wikipedia.org/wiki/Money_flow_index # diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index fecc3a7..4ba151b 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -5,6 +5,10 @@ def self.symbol "mi" end + def self.min_data_size(ema_period: 9, sum_period: 25) + (ema_period * 2) + sum_period - 2 + end + # Calculates the mass index (MI) for the data over the given period # https://en.wikipedia.org/wiki/Mass_index # diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 2d461b4..af46779 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -5,6 +5,10 @@ def self.symbol "nvi" end + def self.min_data_size(**params) + 1 + end + # Calculates the negative volume index (NVI) for the data # https://en.wikipedia.org/wiki/Negative_volume_index # diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 129b98d..dc928ed 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -5,6 +5,10 @@ def self.symbol "obv" end + def self.min_data_size(**params) + 1 + end + # Calculates the on-balance volume (OBV) for the data over the given period # https://en.wikipedia.org/wiki/On-balance_volume # diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index d09524e..12b4f10 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -5,6 +5,10 @@ def self.symbol "obv_mean" end + def self.min_data_size(period: 10) + period + end + # Calculates the on-balance volume mean (OBV mean) for the data over the given period # https://en.wikipedia.org/wiki/On-balance_volume # diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 951f533..713aa39 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -5,6 +5,10 @@ def self.symbol "rsi" end + def self.min_data_size(period: 14, **params) + period + 1 + end + # Calculates the relative strength index for the data over the given period # https://en.wikipedia.org/wiki/Relative_strength_index # diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 4a485d7..c0d7576 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -5,8 +5,8 @@ def self.symbol "sma" end - def self.min_data_size(options) - options[:period] + def self.min_data_size(period: 30, **params) + period end def self.validate_options(options) diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 233ca7f..b06be6b 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -5,6 +5,10 @@ def self.symbol "sr" end + def self.min_data_size(period: 14, signal_period: 3) + period + signal_period - 1 + end + # Calculates the stochastic oscillator (%K) for the data over the given period # https://en.wikipedia.org/wiki/Stochastic_oscillator # diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 5fcfb67..d5091ff 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -5,6 +5,10 @@ def self.symbol "trix" end + def self.min_data_size(period: 15, **params) + (period * 3) - 1 + end + # Calculates the triple exponential average (Trix) for the data over the given period # https://en.wikipedia.org/wiki/Trix_(technical_analysis) # diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index a39dc37..98d4c01 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -5,6 +5,10 @@ def self.symbol "tsi" end + def self.min_data_size(low_period: 13, high_period: 25, **params) + low_period + high_period + end + # Calculates the true strenth index for the data over the given period # https://en.wikipedia.org/wiki/True_strength_index # diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index c1b1541..45e06ed 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -5,6 +5,10 @@ def self.symbol "uo" end + def self.min_data_size(long_period: 28, **params) + long_period + 1 + end + # Calculates the ultimate oscillator for the data over the given period # https://en.wikipedia.org/wiki/Ultimate_oscillator # diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 2f99431..b59dc71 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -5,6 +5,10 @@ def self.symbol "vi" end + def self.min_data_size(period: 14) + period + 1 + end + # Calculates the vortex indicatorfor the data over the given period # https://en.wikipedia.org/wiki/Vortex_indicator # diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index 3a4491c..d3cac16 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -5,6 +5,10 @@ def self.symbol "vpt" end + def self.min_data_size(**params) + 2 + end + # Calculates the volume-price trend (VPT) for the data # https://en.wikipedia.org/wiki/Volume%E2%80%93price_trend # diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index e807fa9..c44b706 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -5,6 +5,10 @@ def self.symbol "wr" end + def self.min_data_size(period: 14) + period + end + # Calculates the Williams %R for the data over the given period # https://en.wikipedia.org/wiki/Williams_%25R # From b37c29a31f2705b35171b029e88a015070f04bf6 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 18:38:14 -0500 Subject: [PATCH 06/84] Symbol to indicator_symbol and add indicator_name - Change self.symbol to self.indicator_symbol - Add self.indicator_name --- lib/technical_analysis/indicators/adi.rb | 6 +++++- lib/technical_analysis/indicators/adtv.rb | 6 +++++- lib/technical_analysis/indicators/adx.rb | 6 +++++- lib/technical_analysis/indicators/ao.rb | 8 ++++++-- lib/technical_analysis/indicators/atr.rb | 6 +++++- lib/technical_analysis/indicators/bb.rb | 6 +++++- lib/technical_analysis/indicators/cci.rb | 6 +++++- lib/technical_analysis/indicators/cmf.rb | 6 +++++- lib/technical_analysis/indicators/cr.rb | 6 +++++- lib/technical_analysis/indicators/dc.rb | 6 +++++- lib/technical_analysis/indicators/dlr.rb | 6 +++++- lib/technical_analysis/indicators/dpo.rb | 6 +++++- lib/technical_analysis/indicators/dr.rb | 6 +++++- lib/technical_analysis/indicators/eom.rb | 6 +++++- lib/technical_analysis/indicators/evm.rb | 2 +- lib/technical_analysis/indicators/fi.rb | 6 +++++- lib/technical_analysis/indicators/ichimoku.rb | 8 ++++++-- lib/technical_analysis/indicators/kc.rb | 6 +++++- lib/technical_analysis/indicators/kst.rb | 6 +++++- lib/technical_analysis/indicators/macd.rb | 6 +++++- lib/technical_analysis/indicators/mfi.rb | 6 +++++- lib/technical_analysis/indicators/mi.rb | 6 +++++- lib/technical_analysis/indicators/nvi.rb | 6 +++++- lib/technical_analysis/indicators/obv.rb | 6 +++++- lib/technical_analysis/indicators/obv_mean.rb | 6 +++++- lib/technical_analysis/indicators/rsi.rb | 6 +++++- lib/technical_analysis/indicators/sma.rb | 6 +++++- lib/technical_analysis/indicators/sr.rb | 6 +++++- lib/technical_analysis/indicators/trix.rb | 6 +++++- lib/technical_analysis/indicators/tsi.rb | 8 ++++++-- lib/technical_analysis/indicators/uo.rb | 8 ++++++-- lib/technical_analysis/indicators/vi.rb | 8 ++++++-- lib/technical_analysis/indicators/vpt.rb | 6 +++++- lib/technical_analysis/indicators/wr.rb | 10 +++++++--- 34 files changed, 173 insertions(+), 41 deletions(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index 6918e37..ed78fdb 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Adi < Indicator - def self.symbol + def self.indicator_symbol "adi" end + def self.indicator_name + "Accumulation/Distribution Index" + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 828e7ba..6d19562 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Adtv < Indicator - def self.symbol + def self.indicator_symbol "adtv" end + def self.indicator_name + "Average Daily Trading Volume" + end + def self.min_data_size(period: 22, **params) period end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 4fcfcc2..4f79409 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Adx < Indicator - def self.symbol + def self.indicator_symbol "adx" end + def self.indicator_name + "Average Directional Index" + end + def self.min_data_size(period: 14) period * 2 end diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 17924d0..78fd8df 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -1,15 +1,19 @@ module TechnicalAnalysis class Ao < Indicator - def self.symbol + def self.indicator_symbol "ao" end + def self.indicator_name + "Awesome Oscillator" + end + def self.min_data_size(long_period: 34, **params) long_period end - # Calculates the Awesome Oscillator for the data over the given period + # Calculates the awesome oscillator for the data over the given period # https://www.tradingview.com/wiki/Awesome_Oscillator_(AO) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low) diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 8e07773..ead8609 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Atr < Indicator - def self.symbol + def self.indicator_symbol "atr" end + def self.indicator_name + "Average True Range" + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 08176b0..e81284c 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Bb < Indicator - def self.symbol + def self.indicator_symbol "bb" end + def self.indicator_name + "Bollinger Bands" + end + def self.min_data_size(period: 20, **params) period end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index c597f0d..644003f 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Cci < Indicator - def self.symbol + def self.indicator_symbol "cci" end + def self.indicator_name + "Commodity Channel Index" + end + def self.min_data_size(period: 20, **params) period end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index b68ffba..4e7d6e4 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Cmf < Indicator - def self.symbol + def self.indicator_symbol "cmf" end + def self.indicator_name + "Chaikin Money Flow" + end + def self.min_data_size(period: 20) period end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 703c955..e67185c 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Cr < Indicator - def self.symbol + def self.indicator_symbol "cr" end + def self.indicator_name + "Cumulative Return" + end + def min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 18c4816..2a49a2d 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Dc < Indicator - def self.symbol + def self.indicator_symbol "dc" end + def self.indicator_name + "Donchian Channel" + end + def self.min_data_size(period: 20, **params) period end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index c7ea36c..54daafd 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Dlr < Indicator - def self.symbol + def self.indicator_symbol "dlr" end + def self.indicator_name + "Daily Log Return" + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index e3f2025..e0bf08f 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Dpo < Indicator - def self.symbol + def self.indicator_symbol "dpo" end + def self.indicator_name + "Detrended Price Oscillator" + end + def self.min_data_size(period: 20, **params) period + (period / 2) end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 7c0cf43..8039b4b 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Dr < Indicator - def self.symbol + def self.indicator_symbol "dr" end + def self.indicator_name + "Daily Return" + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 400dada..a848fe1 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Eom < Indicator - def self.symbol + def self.indicator_symbol "eom" end + def self.indicator_name + "Ease of Movement" + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index b334394..705ca23 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -1,7 +1,7 @@ module TechnicalAnalysis Evm = Eom - def self.symbol + def self.indicator_symbol "evm" end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 9b534d2..c1120cc 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Fi < Indicator - def self.symbol + def self.indicator_symbol "fi" end + def self.indicator_name + "Force Index" + end + def self.min_data_size(**params) 2 end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index cae5e63..048ac6e 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -1,15 +1,19 @@ module TechnicalAnalysis class Ichimoku < Indicator - def self.symbol + def self.indicator_symbol "ichimoku" end + def self.indicator_name + "Ichimoku Kinko Hyo" + end + def self.min_data_size(medium_period: 26, high_period: 52, **params) high_period + medium_period - 2 end - # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimooku) for the data over the given period + # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimoku) for the data over the given period # 1. tenkan_sen (Conversion Line) # 2. kijun_sen (Base Line) # 3. senkou_span_a (Leading Span A) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index aa6150d..d94d9ce 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Kc < Indicator - def self.symbol + def self.indicator_symbol "kc" end + def self.indicator_name + "Keltner Channel" + end + def self.min_data_size(period: 10) period end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index a0e08d6..3810f19 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Kst < Indicator - def self.symbol + def self.indicator_symbol "kst" end + def self.indicator_name + "Know Sure Thing" + end + def self.min_data_size(roc4: 30, sma4: 15, **params) roc4 + sma4 - 1 end diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index d7c9aad..b9f73f0 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Macd < Indicator - def self.symbol + def self.indicator_symbol "macd" end + def self.indicator_name + "Moving Average Convergence Divergence" + end + def self.min_data_size(slow_period: 26, signal_period: 9, **params) slow_period + signal_period end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 028d878..2c34e28 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Mfi < Indicator - def self.symbol + def self.indicator_symbol "mfi" end + def self.indicator_name + "Money Flow Index" + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 4ba151b..a37e04e 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Mi < Indicator - def self.symbol + def self.indicator_symbol "mi" end + def self.indicator_name + "Mass Index" + end + def self.min_data_size(ema_period: 9, sum_period: 25) (ema_period * 2) + sum_period - 2 end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index af46779..835a62c 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Nvi < Indicator - def self.symbol + def self.indicator_symbol "nvi" end + def self.indicator_name + "Negative Volume Index" + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index dc928ed..1ab074b 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Obv < Indicator - def self.symbol + def self.indicator_symbol "obv" end + def self.indicator_name + "On-balance Volume" + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 12b4f10..08fe406 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class ObvMean < Indicator - def self.symbol + def self.indicator_symbol "obv_mean" end + def self.indicator_name + "On-balance Volume Mean" + end + def self.min_data_size(period: 10) period end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 713aa39..de9ff0c 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Rsi < Indicator - def self.symbol + def self.indicator_symbol "rsi" end + def self.indicator_name + "Relative Strength Index" + end + def self.min_data_size(period: 14, **params) period + 1 end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index c0d7576..50121a5 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Sma < Indicator - def self.symbol + def self.indicator_symbol "sma" end + def self.indicator_name + "Simple Moving Average" + end + def self.min_data_size(period: 30, **params) period end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index b06be6b..0a36a5e 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Sr < Indicator - def self.symbol + def self.indicator_symbol "sr" end + def self.indicator_name + "Stochastic Oscillator" + end + def self.min_data_size(period: 14, signal_period: 3) period + signal_period - 1 end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index d5091ff..218d737 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Trix < Indicator - def self.symbol + def self.indicator_symbol "trix" end + def self.indicator_name + "Triple Exponential Average" + end + def self.min_data_size(period: 15, **params) (period * 3) - 1 end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 98d4c01..72056d6 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -1,15 +1,19 @@ module TechnicalAnalysis class Tsi < Indicator - def self.symbol + def self.indicator_symbol "tsi" end + def self.indicator_name + "True Strength Index" + end + def self.min_data_size(low_period: 13, high_period: 25, **params) low_period + high_period end - # Calculates the true strenth index for the data over the given period + # Calculates the true strength index (TSI) for the data over the given period # https://en.wikipedia.org/wiki/True_strength_index # # @param data [Array] Array of hashes with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index 45e06ed..a141964 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -1,15 +1,19 @@ module TechnicalAnalysis class Uo < Indicator - def self.symbol + def self.indicator_symbol "uo" end + def self.indicator_name + "Ultimate Oscillator" + end + def self.min_data_size(long_period: 28, **params) long_period + 1 end - # Calculates the ultimate oscillator for the data over the given period + # Calculates the ultimate oscillator (UO) for the data over the given period # https://en.wikipedia.org/wiki/Ultimate_oscillator # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index b59dc71..6f2b802 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -1,15 +1,19 @@ module TechnicalAnalysis class Vi < Indicator - def self.symbol + def self.indicator_symbol "vi" end + def self.indicator_name + "Vortex Indicator" + end + def self.min_data_size(period: 14) period + 1 end - # Calculates the vortex indicatorfor the data over the given period + # Calculates the vortex indicator (VI) for the data over the given period # https://en.wikipedia.org/wiki/Vortex_indicator # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index d3cac16..be9d3d4 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -1,10 +1,14 @@ module TechnicalAnalysis class Vpt < Indicator - def self.symbol + def self.indicator_symbol "vpt" end + def self.indicator_name + "Volume-price Trend" + end + def self.min_data_size(**params) 2 end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index c44b706..9b8d9c7 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -1,19 +1,23 @@ module TechnicalAnalysis class Wr < Indicator - def self.symbol + def self.indicator_symbol "wr" end + def self.indicator_name + "Williams %R" + end + def self.min_data_size(period: 14) period end - # Calculates the Williams %R for the data over the given period + # Calculates the Williams %R (WR) for the data over the given period # https://en.wikipedia.org/wiki/Williams_%25R # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) - # @param period [Integer] The given look-back period to calculate the Williams %R + # @param period [Integer] The given look-back period to calculate the WR # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close) From 37280f8138291d201ee61908f7a9288bcff188df Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 20:14:34 -0500 Subject: [PATCH 07/84] Add valid_options and validate_options - Add valid_options method to each indicator - Add validate_options method to each indicator - Add validate_options method to Validation helper --- lib/technical_analysis/helpers/validation.rb | 8 ++++++++ lib/technical_analysis/indicators/adi.rb | 13 ++++++++++++- lib/technical_analysis/indicators/adtv.rb | 8 ++++++++ lib/technical_analysis/indicators/adx.rb | 8 ++++++++ lib/technical_analysis/indicators/ao.rb | 8 ++++++++ lib/technical_analysis/indicators/atr.rb | 8 ++++++++ lib/technical_analysis/indicators/bb.rb | 8 ++++++++ lib/technical_analysis/indicators/cci.rb | 10 +++++++++- lib/technical_analysis/indicators/cmf.rb | 8 ++++++++ lib/technical_analysis/indicators/cr.rb | 10 +++++++++- lib/technical_analysis/indicators/dc.rb | 8 ++++++++ lib/technical_analysis/indicators/dlr.rb | 8 ++++++++ lib/technical_analysis/indicators/dpo.rb | 8 ++++++++ lib/technical_analysis/indicators/dr.rb | 8 ++++++++ lib/technical_analysis/indicators/eom.rb | 8 ++++++++ lib/technical_analysis/indicators/fi.rb | 8 ++++++++ lib/technical_analysis/indicators/ichimoku.rb | 8 ++++++++ lib/technical_analysis/indicators/kc.rb | 8 ++++++++ lib/technical_analysis/indicators/kst.rb | 10 +++++++++- lib/technical_analysis/indicators/macd.rb | 8 ++++++++ lib/technical_analysis/indicators/mfi.rb | 8 ++++++++ lib/technical_analysis/indicators/mi.rb | 8 ++++++++ lib/technical_analysis/indicators/nvi.rb | 9 +++++++++ lib/technical_analysis/indicators/obv.rb | 9 +++++++++ lib/technical_analysis/indicators/obv_mean.rb | 8 ++++++++ lib/technical_analysis/indicators/rsi.rb | 8 ++++++++ lib/technical_analysis/indicators/sma.rb | 9 ++++++--- lib/technical_analysis/indicators/sr.rb | 8 ++++++++ lib/technical_analysis/indicators/trix.rb | 8 ++++++++ lib/technical_analysis/indicators/tsi.rb | 8 ++++++++ lib/technical_analysis/indicators/uo.rb | 8 ++++++++ lib/technical_analysis/indicators/vi.rb | 8 ++++++++ lib/technical_analysis/indicators/vpt.rb | 9 +++++++++ lib/technical_analysis/indicators/wr.rb | 8 ++++++++ 34 files changed, 280 insertions(+), 7 deletions(-) diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 6366577..07c510f 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -12,6 +12,14 @@ def self.validate_length(data, size) raise ValidationError.new "Not enough data for that period" if data.size < size end + def self.Validation.validate_options(options, valid_options) + raise ValidationError.new "Options must be a hash." unless options.respond_to? :keys + raise ValidationError.new "No valid options provided." unless valid_options + + return true if (options.keys - valid_options).empty? + raise ValidationError.new "Invalid options provided. Valid options are #{VALID_OPTIONS.join(", ")}" + end + class ValidationError < StandardError; end end diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index ed78fdb..92cecba 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,6 +1,8 @@ module TechnicalAnalysis class Adi < Indicator + VALID_OPTIONS = [].freeze + def self.indicator_symbol "adi" end @@ -9,11 +11,20 @@ def self.indicator_name "Accumulation/Distribution Index" end + def self.valid_options + [] + end + + def self.validate_options(options) + return true if options == {} + raise ValidationError.new "This indicator doesn't accept any options." + end + def self.min_data_size(**params) 1 end - # Calculates the Accumulation/Distribution Index for the given data + # Calculates the Accumulation/Distribution Index (ADI) for the given data # https://en.wikipedia.org/wiki/Accumulation/distribution_index # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 6d19562..3a0b7e3 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -9,6 +9,14 @@ def self.indicator_name "Average Daily Trading Volume" end + def self.valid_options + %i(period volume_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 22, **params) period end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 4f79409..cdb5a90 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -9,6 +9,14 @@ def self.indicator_name "Average Directional Index" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period * 2 end diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 78fd8df..e5783db 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -9,6 +9,14 @@ def self.indicator_name "Awesome Oscillator" end + def self.valid_options + %i(short_period long_period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(long_period: 34, **params) long_period end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index ead8609..232c8b8 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -9,6 +9,14 @@ def self.indicator_name "Average True Range" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index e81284c..979a809 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -9,6 +9,14 @@ def self.indicator_name "Bollinger Bands" end + def self.valid_options + %i(period standard_deviations price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 20, **params) period end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 644003f..56eda6f 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -9,11 +9,19 @@ def self.indicator_name "Commodity Channel Index" end + def self.valid_options + %i(period constant) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 20, **params) period end - # Calculates the commodity channel index for the data over the given period + # Calculates the commodity channel index (CCI) for the data over the given period # https://en.wikipedia.org/wiki/Commodity_channel_index # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 4e7d6e4..a82cfa8 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -9,6 +9,14 @@ def self.indicator_name "Chaikin Money Flow" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 20) period end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index e67185c..d60ad51 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -9,11 +9,19 @@ def self.indicator_name "Cumulative Return" end + def self.valid_options + %i(price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def min_data_size(**params) 1 end - # Calculates the cumulative return for the data over the given period + # Calculates the cumulative return (CR) for the data over the given period # https://www.investopedia.com/terms/c/cumulativereturn.asp # # @param data [Array] Array of hashes with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 2a49a2d..f2119b0 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -9,6 +9,14 @@ def self.indicator_name "Donchian Channel" end + def self.valid_options + %i(period price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 20, **params) period end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 54daafd..010d9de 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -9,6 +9,14 @@ def self.indicator_name "Daily Log Return" end + def self.valid_options + %i(price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index e0bf08f..c943c85 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -9,6 +9,14 @@ def self.indicator_name "Detrended Price Oscillator" end + def self.valid_options + %i(period price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 20, **params) period + (period / 2) end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 8039b4b..a0d5d40 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -9,6 +9,14 @@ def self.indicator_name "Daily Return" end + def self.valid_options + %i(price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index a848fe1..5d7035c 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -9,6 +9,14 @@ def self.indicator_name "Ease of Movement" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index c1120cc..c2eba24 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -9,6 +9,14 @@ def self.indicator_name "Force Index" end + def self.valid_options + [] + end + + def self.validate_options(options) + true + end + def self.min_data_size(**params) 2 end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 048ac6e..b53391f 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -9,6 +9,14 @@ def self.indicator_name "Ichimoku Kinko Hyo" end + def self.valid_options + %i(low_period medium_period high_period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(medium_period: 26, high_period: 52, **params) high_period + medium_period - 2 end diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index d94d9ce..667420d 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -9,6 +9,14 @@ def self.indicator_name "Keltner Channel" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 10) period end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 3810f19..da2112f 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -9,11 +9,19 @@ def self.indicator_name "Know Sure Thing" end + def self.valid_options + %i(period roc1 roc2 roc3 roc4 sma1 sma2 sma3 sma4 price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(roc4: 30, sma4: 15, **params) roc4 + sma4 - 1 end - # Calculates the know sure thing for the data over the given period + # Calculates the know sure thing (KST) for the data over the given period # https://en.wikipedia.org/wiki/KST_oscillator # # @param data [Array] Array of hashes with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index b9f73f0..c382f43 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -9,6 +9,14 @@ def self.indicator_name "Moving Average Convergence Divergence" end + def self.valid_options + %i(slow_period signal_period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(slow_period: 26, signal_period: 9, **params) slow_period + signal_period end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 2c34e28..8fdf21d 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -9,6 +9,14 @@ def self.indicator_name "Money Flow Index" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index a37e04e..f8903a2 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -9,6 +9,14 @@ def self.indicator_name "Mass Index" end + def self.valid_options + %i(ema_period sum_period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(ema_period: 9, sum_period: 25) (ema_period * 2) + sum_period - 2 end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 835a62c..8af0bc8 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -9,6 +9,15 @@ def self.indicator_name "Negative Volume Index" end + def self.valid_options + [] + end + + def self.validate_options(options) + return true if options == {} + raise ValidationError.new "This indicator doesn't accept any options." + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 1ab074b..62e6617 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -9,6 +9,15 @@ def self.indicator_name "On-balance Volume" end + def self.valid_options + [] + end + + def self.validate_options(options) + return true if options == {} + raise ValidationError.new "This indicator doesn't accept any options." + end + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 08fe406..eed4f9e 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -9,6 +9,14 @@ def self.indicator_name "On-balance Volume Mean" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 10) period end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index de9ff0c..ae14d5d 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -9,6 +9,14 @@ def self.indicator_name "Relative Strength Index" end + def self.valid_options + %i(period price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14, **params) period + 1 end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 50121a5..418e68e 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -13,12 +13,15 @@ def self.min_data_size(period: 30, **params) period end + def self.valid_options + %i(period price_key) + end + def self.validate_options(options) - return true if (options.keys - [:period, :price_key]).empty? - raise "Invalid options!" + Validation.validate_options(options, valid_options) end - # Calculates the simple moving average for the data over the given period + # Calculates the simple moving average (SMA) for the data over the given period # https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average # # @param data [Array] Array of hashes with keys (:date_time, :value) diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 0a36a5e..d4ddfa3 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -9,6 +9,14 @@ def self.indicator_name "Stochastic Oscillator" end + def self.valid_options + %i(period signal_period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14, signal_period: 3) period + signal_period - 1 end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 218d737..aab2918 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -9,6 +9,14 @@ def self.indicator_name "Triple Exponential Average" end + def self.valid_options + %i(period price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 15, **params) (period * 3) - 1 end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 72056d6..f7b0b04 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -9,6 +9,14 @@ def self.indicator_name "True Strength Index" end + def self.valid_options + %i(low_period high_period price_key) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(low_period: 13, high_period: 25, **params) low_period + high_period end diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index a141964..f960227 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -9,6 +9,14 @@ def self.indicator_name "Ultimate Oscillator" end + def self.valid_options + %i(short_period medium_period long_period short_weight medium_weight long_weight) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(long_period: 28, **params) long_period + 1 end diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 6f2b802..8500e7b 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -9,6 +9,14 @@ def self.indicator_name "Vortex Indicator" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period + 1 end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index be9d3d4..5eacf78 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -9,6 +9,15 @@ def self.indicator_name "Volume-price Trend" end + def self.valid_options + [] + end + + def self.validate_options(options) + return true if options == {} + raise ValidationError.new "This indicator doesn't accept any options." + end + def self.min_data_size(**params) 2 end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 9b8d9c7..4fb634b 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -9,6 +9,14 @@ def self.indicator_name "Williams %R" end + def self.valid_options + %i(period) + end + + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + def self.min_data_size(period: 14) period end From fd5a29e33d98c45b4160d4798cc25c98c1c48bf7 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 20:15:24 -0500 Subject: [PATCH 08/84] Add methods to indicators - Add indicator_symbol - Add indicator_name - Add validate_options - Add valid_options --- .../indicators/indicator.rb | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index eb19811..7988ece 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -2,14 +2,14 @@ module TechnicalAnalysis class Indicator CALCULATIONS = [ + :indicator_name, + :indicator_symbol, :min_data_size, :technicals, + :valid_options, + :validate_options, ].freeze - def self.symbol - raise "#{self.name} did not implement symbol" - end - def self.roster [ TechnicalAnalysis::Adi, @@ -52,7 +52,7 @@ def self.roster # Finds the applicable indicator and returns an instance def self.find(indicator_symbol) self.roster.each do |indicator| - return indicator if indicator.symbol == indicator_symbol + return indicator if indicator.indicator_symbol == indicator_symbol end nil @@ -65,11 +65,13 @@ def self.calculate(indicator_symbol, data, calculation, options={}) indicator = find(indicator_symbol) raise "Indicator not found!" if indicator.nil? - indicator.validate_options(options) - case calculation + when :indicator_name; indicator.indicator_name + when :indicator_symbol; indicator.indicator_symbol when :technicals; indicator.calculate(data, options) when :min_data_size; indicator.min_data_size(options) + when :valid_options; indicator.valid_options + when :validate_options; indicator.validate_options(options) else nil end end @@ -86,5 +88,15 @@ def self.validate_options(options) false end + # Get the symbol string of the indicator + def self.indicator_symbol + raise "#{self.name} did not implement indicator_symbol" + end + + # Get the name string of the indicator + def self.indicator_name + raise "#{self.name} did not implement indicator_name" + end + end end From e2c2f404d67dbbdbd7701ed520316df105871b39 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 20:17:21 -0500 Subject: [PATCH 09/84] Add default valid_options method to indicator --- lib/technical_analysis/indicators/indicator.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 7988ece..2b429f8 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -88,12 +88,18 @@ def self.validate_options(options) false end - # Get the symbol string of the indicator + # Returns the valid options for the indicator + def self.valid_options + raise "#{self.name} did not implement valid_options" + [] + end + + # Returns the symbol string of the indicator def self.indicator_symbol raise "#{self.name} did not implement indicator_symbol" end - # Get the name string of the indicator + # Returns the name string of the indicator def self.indicator_name raise "#{self.name} did not implement indicator_name" end From 3df4155d9f3596d803bd9a439d57d431113ac984 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 1 Feb 2019 20:59:20 -0500 Subject: [PATCH 10/84] Sort output by date_time desc, update specs --- lib/technical_analysis/helpers/validation.rb | 2 +- lib/technical_analysis/indicators/adi.rb | 2 +- lib/technical_analysis/indicators/adtv.rb | 2 +- lib/technical_analysis/indicators/adx.rb | 2 +- lib/technical_analysis/indicators/ao.rb | 2 +- lib/technical_analysis/indicators/atr.rb | 2 +- lib/technical_analysis/indicators/bb.rb | 2 +- lib/technical_analysis/indicators/cci.rb | 2 +- lib/technical_analysis/indicators/cmf.rb | 2 +- lib/technical_analysis/indicators/cr.rb | 2 +- lib/technical_analysis/indicators/dc.rb | 2 +- lib/technical_analysis/indicators/dlr.rb | 2 +- lib/technical_analysis/indicators/dpo.rb | 2 +- lib/technical_analysis/indicators/dr.rb | 2 +- lib/technical_analysis/indicators/eom.rb | 2 +- lib/technical_analysis/indicators/fi.rb | 2 +- lib/technical_analysis/indicators/ichimoku.rb | 2 +- lib/technical_analysis/indicators/kc.rb | 2 +- lib/technical_analysis/indicators/kst.rb | 2 +- lib/technical_analysis/indicators/macd.rb | 2 +- lib/technical_analysis/indicators/mfi.rb | 2 +- lib/technical_analysis/indicators/mi.rb | 2 +- lib/technical_analysis/indicators/nvi.rb | 2 +- lib/technical_analysis/indicators/obv.rb | 2 +- lib/technical_analysis/indicators/obv_mean.rb | 2 +- lib/technical_analysis/indicators/rsi.rb | 2 +- lib/technical_analysis/indicators/sr.rb | 2 +- lib/technical_analysis/indicators/trix.rb | 2 +- lib/technical_analysis/indicators/tsi.rb | 2 +- lib/technical_analysis/indicators/uo.rb | 2 +- lib/technical_analysis/indicators/vi.rb | 2 +- lib/technical_analysis/indicators/vpt.rb | 2 +- lib/technical_analysis/indicators/wr.rb | 2 +- .../technical_analysis/indicators/adi_spec.rb | 124 +++++++++--------- .../indicators/adtv_spec.rb | 82 ++++++------ .../technical_analysis/indicators/adx_spec.rb | 70 +++++----- spec/technical_analysis/indicators/ao_spec.rb | 58 ++++---- .../technical_analysis/indicators/atr_spec.rb | 96 +++++++------- spec/technical_analysis/indicators/bb_spec.rb | 86 ++++++------ .../technical_analysis/indicators/cci_spec.rb | 86 ++++++------ .../technical_analysis/indicators/cmf_spec.rb | 86 ++++++------ spec/technical_analysis/indicators/cr_spec.rb | 124 +++++++++--------- spec/technical_analysis/indicators/dc_spec.rb | 86 ++++++------ .../technical_analysis/indicators/dlr_spec.rb | 124 +++++++++--------- .../technical_analysis/indicators/dpo_spec.rb | 66 +++++----- spec/technical_analysis/indicators/dr_spec.rb | 124 +++++++++--------- .../technical_analysis/indicators/eom_spec.rb | 96 +++++++------- .../technical_analysis/indicators/evm_spec.rb | 96 +++++++------- spec/technical_analysis/indicators/fi_spec.rb | 122 ++++++++--------- .../indicators/ichimoku_spec.rb | 68 +++++----- spec/technical_analysis/indicators/kc_spec.rb | 106 +++++++-------- .../technical_analysis/indicators/kst_spec.rb | 38 +++--- .../indicators/macd_spec.rb | 58 ++++---- .../technical_analysis/indicators/mfi_spec.rb | 96 +++++++------- spec/technical_analysis/indicators/mi_spec.rb | 44 +++---- .../technical_analysis/indicators/nvi_spec.rb | 124 +++++++++--------- .../indicators/obv_mean_spec.rb | 104 +++++++-------- .../technical_analysis/indicators/obv_spec.rb | 124 +++++++++--------- .../technical_analysis/indicators/rsi_spec.rb | 96 +++++++------- .../technical_analysis/indicators/sma_spec.rb | 116 ++++++++-------- spec/technical_analysis/indicators/sr_spec.rb | 94 ++++++------- .../indicators/trix_spec.rb | 38 +++--- .../technical_analysis/indicators/tsi_spec.rb | 50 +++---- spec/technical_analysis/indicators/uo_spec.rb | 68 +++++----- spec/technical_analysis/indicators/vi_spec.rb | 96 +++++++------- .../technical_analysis/indicators/vpt_spec.rb | 122 ++++++++--------- spec/technical_analysis/indicators/wr_spec.rb | 98 +++++++------- 67 files changed, 1566 insertions(+), 1566 deletions(-) diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 07c510f..6d58ec7 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -12,7 +12,7 @@ def self.validate_length(data, size) raise ValidationError.new "Not enough data for that period" if data.size < size end - def self.Validation.validate_options(options, valid_options) + def self.validate_options(options, valid_options) raise ValidationError.new "Options must be a hash." unless options.respond_to? :keys raise ValidationError.new "No valid options provided." unless valid_options diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index 92cecba..56315c9 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -51,7 +51,7 @@ def self.calculate(data) ads << { date_time: values[:date_time], value: ad } end - ads + ads.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 3a0b7e3..af516d7 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -45,7 +45,7 @@ def self.calculate(data, period: 22, volume_key: :value) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index cdb5a90..82a4ef1 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -83,7 +83,7 @@ def self.calculate(data, period: 14) prev_price = v end - output + output.sort_by_hash_date_time_desc end def self.calculate_dm(current_price, prev_price) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index e5783db..db24bb0 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -52,7 +52,7 @@ def self.calculate(data, short_period: 5, long_period: 34) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 232c8b8..87e90d0 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 14) prev_price = v end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 979a809..784d779 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 56eda6f..692b029 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -51,7 +51,7 @@ def self.calculate(data, period: 20, constant: 0.015) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index a82cfa8..f4055fd 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -52,7 +52,7 @@ def self.calculate(data, period: 20) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index d60ad51..744fff3 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -40,7 +40,7 @@ def self.calculate(data, price_key: :value) output << { date_time: v[:date_time], value: ((v[price_key] - start_price) / start_price) } end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index f2119b0..e6fcef6 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -53,7 +53,7 @@ def self.calculate(data, period: 20, price_key: :value) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 010d9de..1d69aeb 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -45,7 +45,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index c943c85..53b75ed 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -52,7 +52,7 @@ def self.calculate(data, period: 20, price_key: :value) index += 1 end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index a0d5d40..4d08941 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -44,7 +44,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 5d7035c..2118a6b 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -52,7 +52,7 @@ def self.calculate(data, period: 14) prev_price = v end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index c2eba24..e406d28 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -41,7 +41,7 @@ def self.calculate(data) prev_price = v end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index b53391f..75832e9 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -66,7 +66,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) index += 1 end - output + output.sort_by_hash_date_time_desc end def self.lowest_low(prices) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 667420d..8482f60 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -61,7 +61,7 @@ def self.calculate(data, period: 10) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index da2112f..b9d5a0b 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -57,7 +57,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: index += 1 end - output + output.sort_by_hash_date_time_desc end def self.calculate_rcma(data, index, price_key, roc, sma) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index c382f43..eb1fcba 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -78,7 +78,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 8fdf21d..90a87d9 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -67,7 +67,7 @@ def self.calculate(data, period: 14) prev_typical_price = typical_price end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index f8903a2..85a4b4b 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -68,7 +68,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 8af0bc8..0f7cf2b 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -51,7 +51,7 @@ def self.calculate(data) prev_price = v end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 62e6617..894a03d 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -53,7 +53,7 @@ def self.calculate(data) prior_close = close end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index eed4f9e..94ff3a5 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -58,7 +58,7 @@ def self.calculate(data, period: 10) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index ae14d5d..3dcb8ae 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -80,7 +80,7 @@ def self.calculate(data, period: 14, price_key: :value) prev_price = v[price_key] end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index d4ddfa3..45c4764 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -66,7 +66,7 @@ def self.calculate(data, period: 14, signal_period: 3) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index aab2918..4d93766 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -74,7 +74,7 @@ def self.calculate(data, period: 15, price_key: :value) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index f7b0b04..a030aa1 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -69,7 +69,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) prev_price = current_price end - output + output.sort_by_hash_date_time_desc end def self.process_ema(current_value, data, multiplier, period, store) diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index f960227..d9e1cf7 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -66,7 +66,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh prior_close = v[:close] end - output + output.sort_by_hash_date_time_desc end def self.calculate_average(period, data) diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 8500e7b..7d05b32 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -63,7 +63,7 @@ def self.calculate(data, period: 14) prev_price = v end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index 5eacf78..040ae9e 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -44,7 +44,7 @@ def self.calculate(data) prev_pvt = pvt end - output + output.sort_by_hash_date_time_desc end end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 4fb634b..40d3594 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -51,7 +51,7 @@ def self.calculate(data, period: 14) end end - output + output.sort_by_hash_date_time_desc end end diff --git a/spec/technical_analysis/indicators/adi_spec.rb b/spec/technical_analysis/indicators/adi_spec.rb index ea56856..dd4f86b 100644 --- a/spec/technical_analysis/indicators/adi_spec.rb +++ b/spec/technical_analysis/indicators/adi_spec.rb @@ -11,69 +11,69 @@ output = TechnicalAnalysis::Adi.calculate(input_data) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>22411774.711174767}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-16199273.599504825}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-37713866.134323865}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-8288954.710482582}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-37374123.7894299}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-16341921.130974408}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-13591269.009762233}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-16955140.819851194}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-17555977.138388995}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-24060850.441556394}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>9915241.57013943}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-25537009.286413625}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-16320985.571510637}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-17952613.497042313}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-22322304.45292461}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-9048353.606900878}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-2596414.5729579534}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>47686098.74235708}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>2052056.5039138943}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>8638028.433174696}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>20488006.51898352}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>52544543.51729703}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>53370009.30364728}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>59576412.70790268}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>14980297.36136794}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-19025685.861899547}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-67251111.0548819}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-31201198.431607798}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13921718.702957403}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-42863658.35269459}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-77157217.68155372}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-104408223.70305927}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-126035061.64521725}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-87657844.24649628}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-57716487.89688186}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-16831219.815120786}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-28229849.61904212}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30619198.70995107}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>7310177.429459017}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28184142.065140743}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>13345403.439446371}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-25774650.00158758}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>27031122.187761355}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>12348220.058324995}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21169236.217537448}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-23482456.813564237}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-59826989.44514345}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-84453563.11062376}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-82088668.90680213}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-109189734.6005822}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-144651314.99705797}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-215519041.4917826}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-249091249.23371798}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-191621153.9435182}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-149563792.60023466}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-155977335.67328295}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-160289759.42328274}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-139000081.24146464}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-220800308.5532927}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-170386118.17770624}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-149339794.90125585}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-112451134.66006838}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-135060226.53761944}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-112451134.66006838} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-149339794.90125585}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-170386118.17770624}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-220800308.5532927}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-139000081.24146464}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-160289759.42328274}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-155977335.67328295}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-149563792.60023466}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-191621153.9435182}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-249091249.23371798}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-215519041.4917826}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-144651314.99705797}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-109189734.6005822}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-82088668.90680213}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-84453563.11062376}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-59826989.44514345}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-23482456.813564237}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21169236.217537448}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>12348220.058324995}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>27031122.187761355}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-25774650.00158758}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>13345403.439446371}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28184142.065140743}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>7310177.429459017}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30619198.70995107}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-28229849.61904212}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-16831219.815120786}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-57716487.89688186}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-87657844.24649628}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-126035061.64521725}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-104408223.70305927}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-77157217.68155372}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-42863658.35269459}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13921718.702957403}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-31201198.431607798}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-67251111.0548819}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-19025685.861899547}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>14980297.36136794}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>59576412.70790268}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>53370009.30364728}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>52544543.51729703}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>20488006.51898352}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>8638028.433174696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>2052056.5039138943}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>47686098.74235708}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-2596414.5729579534}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-9048353.606900878}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-22322304.45292461}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-17952613.497042313}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-16320985.571510637}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-25537009.286413625}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>9915241.57013943}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-24060850.441556394}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-17555977.138388995}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-16955140.819851194}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-13591269.009762233}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-16341921.130974408}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-37374123.7894299}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-8288954.710482582}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-37713866.134323865}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-16199273.599504825}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>22411774.711174767} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/adtv_spec.rb b/spec/technical_analysis/indicators/adtv_spec.rb index 5cc33a4..6fa3b5e 100644 --- a/spec/technical_analysis/indicators/adtv_spec.rb +++ b/spec/technical_analysis/indicators/adtv_spec.rb @@ -10,48 +10,48 @@ output = TechnicalAnalysis::Adtv.calculate(input_data, period: 22, volume_key: :volume) expected_output = [ - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40280851.81818182}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>40218699.09090909}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>39911139.54545455}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>39824262.72727273}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>40152941.81818182}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>41528709.54545455}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>42322760.0}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>42936325.90909091}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>43356214.09090909}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>44938230.0}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>45044807.27272727}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>44360389.09090909}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>44572670.90909091}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>45123980.0}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>45067164.09090909}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>44876704.54545455}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>45010174.09090909}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>45124760.0}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>44587813.63636363}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>42390465.90909091}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>41281670.90909091}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>42644592.72727273}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>43220792.72727273}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43683765.90909091}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>43567240.90909091}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43095846.81818182}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>42937879.09090909}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>41719976.81818182}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>41780250.0}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>43062381.81818182}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>45511067.27272727}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>44124274.09090909}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>45353256.36363637}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>46625296.36363637}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>46492490.90909091}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46189911.36363637}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>45721516.81818182}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>47975301.36363637}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>48793455.45454545}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>49431352.72727273}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>49513676.36363637}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>49407791.81818182}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>49513676.36363637} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>49431352.72727273}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>48793455.45454545}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>47975301.36363637}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>45721516.81818182}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46189911.36363637}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>46492490.90909091}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>46625296.36363637}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>45353256.36363637}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>44124274.09090909}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>45511067.27272727}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>43062381.81818182}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>41780250.0}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>41719976.81818182}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>42937879.09090909}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43095846.81818182}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>43567240.90909091}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43683765.90909091}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>43220792.72727273}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>42644592.72727273}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>41281670.90909091}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>42390465.90909091}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>44587813.63636363}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>45124760.0}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>45010174.09090909}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>44876704.54545455}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>45067164.09090909}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>45123980.0}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>44572670.90909091}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>44360389.09090909}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>45044807.27272727}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>44938230.0}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>43356214.09090909}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>42936325.90909091}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>42322760.0}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>41528709.54545455}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>40152941.81818182}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>39824262.72727273}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>39911139.54545455}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>40218699.09090909}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40280851.81818182} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/adx_spec.rb b/spec/technical_analysis/indicators/adx_spec.rb index a37197a..06149c5 100644 --- a/spec/technical_analysis/indicators/adx_spec.rb +++ b/spec/technical_analysis/indicators/adx_spec.rb @@ -10,42 +10,42 @@ output = TechnicalAnalysis::Adx.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:adx=>48.08801057392937, :di_neg=>35.92768510004254, :di_pos=>16.527665969119678}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/ao_spec.rb b/spec/technical_analysis/indicators/ao_spec.rb index b0313ee..027cdd2 100644 --- a/spec/technical_analysis/indicators/ao_spec.rb +++ b/spec/technical_analysis/indicators/ao_spec.rb @@ -10,36 +10,36 @@ output = TechnicalAnalysis::Ao.calculate(input_data, short_period: 5, long_period: 34) expected_output = [ - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-28.26261029411762}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-29.739166176470576}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-28.547813235294086}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-27.130989705882314}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-25.05331323529407}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-21.886519117646998}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-19.392987941176415}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-19.071752647058815}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-19.51995852941178}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-20.365870294117656}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-21.579664411764696}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21.92503676470585}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-20.811713235294178}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-20.12868382352943}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18.865919117647138}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18.17262500000004}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-18.17277205882357}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-18.88406617647061}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-19.609007352941205}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-21.124477941176536}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.471330882352987}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.97706617647063}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.924007352941203}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-19.633272058823536}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-16.73956617647059}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-16.804919117647017}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-16.838043823529347}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-17.41204382352936}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-17.8071908823529}, {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-17.518757058823525}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-17.8071908823529}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-17.41204382352936}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-16.838043823529347}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-16.804919117647017}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-16.73956617647059}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-19.633272058823536}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.924007352941203}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.97706617647063}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.471330882352987}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-21.124477941176536}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-19.609007352941205}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-18.88406617647061}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-18.17277205882357}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18.17262500000004}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18.865919117647138}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-20.12868382352943}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-20.811713235294178}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21.92503676470585}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-21.579664411764696}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-20.365870294117656}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-19.51995852941178}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-19.071752647058815}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-19.392987941176415}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-21.886519117646998}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-25.05331323529407}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-27.130989705882314}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-28.547813235294086}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-29.739166176470576}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-28.26261029411762} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/atr_spec.rb b/spec/technical_analysis/indicators/atr_spec.rb index 9d85ddb..ea42966 100644 --- a/spec/technical_analysis/indicators/atr_spec.rb +++ b/spec/technical_analysis/indicators/atr_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Atr.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>7.449807142857144}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>7.339820918367347}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>7.326262281341107}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>7.199386404102457}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>7.884430232380852}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>7.98625664435365}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>7.63938116975696}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>7.542996800488605}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>7.244925600453705}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>7.173145200421298}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>7.423634828962634}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>7.302653769751019}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>7.391749929054517}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>7.233053505550622}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>7.109942540868436}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>7.212089502234975}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>7.43622596636105}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>7.1707812544781175}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>6.9928683077296805}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>6.828377714320418}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>6.618493591868961}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>6.649315478164034}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>6.538650086866604}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>6.307317937804704}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>6.311080942247224}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>6.471003732086706}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>6.456646322651943}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>6.4540287281768025}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>6.475883819021315}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>6.355463546234078}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>6.1365018643602145}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>5.946037445477343}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>5.926320485086102}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>5.904440450437095}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>5.739123275405874}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>5.926328755734025}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>5.989448130324453}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>6.170916121015564}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>6.084422112371596}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>6.400534818630767}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>6.450496617299998}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>6.273318287492855}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>6.048795552671939}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>5.946738727481086}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>6.6591145326610075}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>6.637742066042365}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>6.3729033470393395}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>6.103013600253306}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>6.195553107965099}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>6.103013600253306} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>6.3729033470393395}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>6.637742066042365}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>6.6591145326610075}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>5.946738727481086}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>6.048795552671939}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>6.273318287492855}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>6.450496617299998}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>6.400534818630767}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>6.084422112371596}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>6.170916121015564}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>5.989448130324453}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>5.926328755734025}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>5.739123275405874}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>5.904440450437095}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>5.926320485086102}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>5.946037445477343}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>6.1365018643602145}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>6.355463546234078}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>6.475883819021315}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>6.4540287281768025}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>6.456646322651943}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>6.471003732086706}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>6.311080942247224}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>6.307317937804704}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>6.538650086866604}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>6.649315478164034}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>6.618493591868961}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>6.828377714320418}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>6.9928683077296805}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>7.1707812544781175}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>7.43622596636105}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>7.212089502234975}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>7.109942540868436}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>7.233053505550622}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>7.391749929054517}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>7.302653769751019}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>7.423634828962634}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>7.173145200421298}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>7.244925600453705}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>7.542996800488605}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>7.63938116975696}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>7.98625664435365}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>7.884430232380852}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>7.199386404102457}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>7.326262281341107}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>7.339820918367347}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>7.449807142857144} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/bb_spec.rb b/spec/technical_analysis/indicators/bb_spec.rb index d948401..6c7bb19 100644 --- a/spec/technical_analysis/indicators/bb_spec.rb +++ b/spec/technical_analysis/indicators/bb_spec.rb @@ -10,50 +10,50 @@ output = TechnicalAnalysis::Bb.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close) expected_output = [ - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>141.07714470666247, :middle_band=>158.1695, :upper_band=>175.26185529333753}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/cci_spec.rb b/spec/technical_analysis/indicators/cci_spec.rb index ba164de..eebdd6c 100644 --- a/spec/technical_analysis/indicators/cci_spec.rb +++ b/spec/technical_analysis/indicators/cci_spec.rb @@ -10,50 +10,50 @@ output = TechnicalAnalysis::Cci.calculate(input_data, period: 20, constant: 0.015) expected_output = [ - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-281.5255251804358}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-198.71238766942466}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-107.40409620543349}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-88.26723659204252}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-121.3842764199079}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-179.88996064655686}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-170.11758119513328}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-176.53554346437872}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-144.29736082195598}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-109.8703962546515}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-129.79321417259732}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-166.092016017792}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-143.70909871161282}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-145.81148745067057}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-130.57777507098388}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-117.06521007698558}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-79.16162769465076}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-67.42425893465922}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-68.8774176049022}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-32.43699792850786}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-60.69535791887537}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-87.66403875835518}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-102.13101656480995}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-118.83020945347108}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-105.1287325078536}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-93.5619842292165}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-77.37092752385674}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-114.79798652194032}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-123.22931274779911}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-108.36683776743406}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-145.86611021295013}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-175.655233047097}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-204.3001270602558}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-205.86763488625635}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-130.89740843118958}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-109.82143904961333}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-82.72457326337747}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-62.94237272962061}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-62.42850721332871}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-162.69069349674928}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-119.01911861945885}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-103.45330536502108}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-48.14847062019609}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-72.7408611895969}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-48.14847062019609} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-103.45330536502108}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-119.01911861945885}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-162.69069349674928}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-62.42850721332871}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-62.94237272962061}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-82.72457326337747}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-109.82143904961333}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-130.89740843118958}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-205.86763488625635}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-204.3001270602558}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-175.655233047097}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-145.86611021295013}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-108.36683776743406}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-123.22931274779911}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-114.79798652194032}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-77.37092752385674}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-93.5619842292165}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-105.1287325078536}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-118.83020945347108}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-102.13101656480995}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-87.66403875835518}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-60.69535791887537}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-32.43699792850786}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-68.8774176049022}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-67.42425893465922}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-79.16162769465076}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-117.06521007698558}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-130.57777507098388}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-145.81148745067057}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-143.70909871161282}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-166.092016017792}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-129.79321417259732}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-109.8703962546515}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-144.29736082195598}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-176.53554346437872}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-170.11758119513328}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-179.88996064655686}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-121.3842764199079}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-88.26723659204252}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-107.40409620543349}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-198.71238766942466}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-281.5255251804358} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/cmf_spec.rb b/spec/technical_analysis/indicators/cmf_spec.rb index cf0f3e3..480530e 100644 --- a/spec/technical_analysis/indicators/cmf_spec.rb +++ b/spec/technical_analysis/indicators/cmf_spec.rb @@ -10,50 +10,50 @@ output = TechnicalAnalysis::Cmf.calculate(input_data, period: 20) expected_output = [ - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>0.010519910116535688}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.002328367522189358}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.0839939173853672}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>0.11517576782439708}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>0.08638139363431603}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>0.06492697386482489}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.00325588286845078}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.06224056395025631}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.016262278292090777}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.004132959703610273}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.02107439975862456}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.09451983283878523}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0864519745264971}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.12097582444999905}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.07707518115228632}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.039334642581608396}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.008559410227273146}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.02808273355873217}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.08707816577338795}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.006195178249247199}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044697234566322144}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.008556645577315109}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.09289096149170357}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.02994416009907359}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.05299093511730075}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.041279122544240626}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.005177700749048257}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>0.008829457014340984}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0635610565928198}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.08160027269601758}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.07883316711924936}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.08053545285645361}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.12311876857928804}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.13433878933016613}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.11185040161958644}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.09771633750350824}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.14870217725852253}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.1421967277504723}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.1171779554311941}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.23384083275693518}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.14338098793972473}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.16209459049078995}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.14148236474171028}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.10900349402409147}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.14148236474171028} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.16209459049078995}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.14338098793972473}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.23384083275693518}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.1171779554311941}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.1421967277504723}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.14870217725852253}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.09771633750350824}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.11185040161958644}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.13433878933016613}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.12311876857928804}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.08053545285645361}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.07883316711924936}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.08160027269601758}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0635610565928198}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>0.008829457014340984}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.005177700749048257}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.041279122544240626}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.05299093511730075}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.02994416009907359}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.09289096149170357}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.008556645577315109}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044697234566322144}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.006195178249247199}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.08707816577338795}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.02808273355873217}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.008559410227273146}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.039334642581608396}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.07707518115228632}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.12097582444999905}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0864519745264971}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.09451983283878523}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.02107439975862456}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.004132959703610273}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.016262278292090777}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.06224056395025631}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.00325588286845078}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>0.06492697386482489}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>0.08638139363431603}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>0.11517576782439708}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.0839939173853672}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.002328367522189358}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>0.010519910116535688} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/cr_spec.rb b/spec/technical_analysis/indicators/cr_spec.rb index 1e93b59..d59ea6c 100644 --- a/spec/technical_analysis/indicators/cr_spec.rb +++ b/spec/technical_analysis/indicators/cr_spec.rb @@ -10,69 +10,69 @@ output = TechnicalAnalysis::Cr.calculate(input_data, price_key: :close) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.04632608983118081}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.054745008154449756}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-0.02098117864856522}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.041918279190725924}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-0.02080486622294706}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.025036364437783783}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.04782474544893549}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-0.03332304844183895}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-0.027416582183629384}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-0.018248336051483294}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.05192400934455856}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-0.031163221228016014}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.046590558469608113}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.06448626966985496}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-0.05981399039097277}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-0.035306563230043594}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-0.020496319478115244}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0854674483184203}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.11142945299069952}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.10182042579450784}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-0.07458015603649674}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.08101555957156079}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.09873495834618948}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.14413540794287485}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.15268656058535732}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.17662097236302726}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.15630096531053028}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-0.14695640675276592}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.18076431436505483}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.21990567285229431}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.22078723498038524}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.24057830475602773}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.2303081059637678}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.23198307400714063}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.20245074271609295}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.20857759950632518}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.2128531758275664}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-0.185348437431128}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.2211839379380262}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.22986732489972234}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.25732798518975625}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.2524353153788514}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.2567108917000926}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.2546392206990788}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.2464847710142373}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.2705954952175255}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.277383523603826}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.2679948869396571}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.29082734605721344}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.3087230572574602}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.3356107021642351}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.35280116366200903}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.3072244016397056}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.3117203684929695}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.3113677436417332}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.30471194957464626}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.30391854365936444}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.3732534050337198}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.34649799444615864}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.34795257195750867}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.3242385507118614}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.33552254595142594}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.3242385507118614} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.34795257195750867}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.34649799444615864}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.3732534050337198}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.30391854365936444}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.30471194957464626}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.3113677436417332}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.3117203684929695}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.3072244016397056}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.35280116366200903}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.3356107021642351}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.3087230572574602}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.29082734605721344}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.2679948869396571}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.277383523603826}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.2705954952175255}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.2464847710142373}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.2546392206990788}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.2567108917000926}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.2524353153788514}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.25732798518975625}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.22986732489972234}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.2211839379380262}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-0.185348437431128}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.2128531758275664}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.20857759950632518}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.20245074271609295}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.23198307400714063}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.2303081059637678}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.24057830475602773}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.22078723498038524}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.21990567285229431}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.18076431436505483}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-0.14695640675276592}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.15630096531053028}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.17662097236302726}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.15268656058535732}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.14413540794287485}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.09873495834618948}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.08101555957156079}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-0.07458015603649674}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.10182042579450784}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.11142945299069952}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0854674483184203}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-0.020496319478115244}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-0.035306563230043594}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-0.05981399039097277}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.06448626966985496}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.046590558469608113}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-0.031163221228016014}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.05192400934455856}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-0.018248336051483294}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-0.027416582183629384}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-0.03332304844183895}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.04782474544893549}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.025036364437783783}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-0.02080486622294706}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.041918279190725924}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-0.02098117864856522}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.054745008154449756}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.04632608983118081}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/dc_spec.rb b/spec/technical_analysis/indicators/dc_spec.rb index 3406351..3734d4b 100644 --- a/spec/technical_analysis/indicators/dc_spec.rb +++ b/spec/technical_analysis/indicators/dc_spec.rb @@ -10,50 +10,50 @@ output = TechnicalAnalysis::Dc.calculate(input_data, period: 20, price_key: :close) expected_output = [ - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>226.87}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:lower_bound=>194.17, :upper_bound=>222.73}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:lower_bound=>192.23, :upper_bound=>222.73}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:lower_bound=>185.86, :upper_bound=>222.73}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:lower_bound=>176.98, :upper_bound=>222.22}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:lower_bound=>176.78, :upper_bound=>222.22}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>208.49}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>204.47}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>194.17}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:lower_bound=>165.48, :upper_bound=>193.53}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>193.53}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>185.86}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:lower_bound=>160.89, :upper_bound=>184.82}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:lower_bound=>156.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:lower_bound=>150.73, :upper_bound=>184.82}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>176.69}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>174.72}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>174.72}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>176.69}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:lower_bound=>150.73, :upper_bound=>184.82}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:lower_bound=>156.83, :upper_bound=>184.82}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:lower_bound=>160.89, :upper_bound=>184.82}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>185.86}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>193.53}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:lower_bound=>165.48, :upper_bound=>193.53}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>194.17}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>204.47}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>208.49}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:lower_bound=>176.78, :upper_bound=>222.22}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:lower_bound=>176.98, :upper_bound=>222.22}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:lower_bound=>185.86, :upper_bound=>222.73}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:lower_bound=>192.23, :upper_bound=>222.73}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:lower_bound=>194.17, :upper_bound=>222.73}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>226.87}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/dlr_spec.rb b/spec/technical_analysis/indicators/dlr_spec.rb index b6452f5..4dcebf6 100644 --- a/spec/technical_analysis/indicators/dlr_spec.rb +++ b/spec/technical_analysis/indicators/dlr_spec.rb @@ -10,69 +10,69 @@ output = TechnicalAnalysis::Dlr.calculate(input_data, price_key: :close) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.047433479205543055}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.008867076040336814}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.03509614368752819}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021617789532325248}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.02179786426382509}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.0043307687122485835}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023651064679340767}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.01511525802908552}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006091481696142526}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009382539847836957}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.03490373037505153}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021661496781179467}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.0160517090105079}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018948623129528868}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004981915647820579}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.025732630512992103}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015235626165565584}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0686329326726632}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028799017690867113}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010755975020512992}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.029877500317357083}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006978328672237313}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.01946981300300202}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.051687201448600596}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.010041492241593453}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.028654045970026604}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.024379198463276127}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011014814954241668}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.04043883708306672}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.04895697028998929}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011307102064021337}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.02572691808848715}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013433080838346925}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.002178525198011193}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.037731825412945244}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.007711763925503673}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005417040583021469}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.034345698370823956}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044985593831335616}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011212092072018474}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03630829170624626}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.00656632250750863}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.00573575767570937}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.002783290222441408}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010880860180775654}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.032520774492099586}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0093498343683261}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.012908878993777004}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.03168848455571821}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.02555848551661011}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.039672259323895565}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.026214701847591528}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.06805256711339175}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006510938359150324}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.0005121966947240164}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009618827546033224}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011404677153263752}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.10492438427688831}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.04180329782029066}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022283003244291597}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01683917971506794}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.01888364670315034}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01683917971506794} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022283003244291597}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.04180329782029066}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.10492438427688831}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011404677153263752}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009618827546033224}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.0005121966947240164}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006510938359150324}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.06805256711339175}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.026214701847591528}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.039672259323895565}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.02555848551661011}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.03168848455571821}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.012908878993777004}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0093498343683261}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.032520774492099586}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010880860180775654}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.002783290222441408}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.00573575767570937}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.00656632250750863}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03630829170624626}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011212092072018474}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044985593831335616}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.034345698370823956}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005417040583021469}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.007711763925503673}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.037731825412945244}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.002178525198011193}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013433080838346925}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.02572691808848715}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011307102064021337}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.04895697028998929}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.04043883708306672}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011014814954241668}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.024379198463276127}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.028654045970026604}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.010041492241593453}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.051687201448600596}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.01946981300300202}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006978328672237313}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.029877500317357083}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010755975020512992}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028799017690867113}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0686329326726632}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015235626165565584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.025732630512992103}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004981915647820579}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018948623129528868}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.0160517090105079}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021661496781179467}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.03490373037505153}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009382539847836957}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006091481696142526}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.01511525802908552}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023651064679340767}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.0043307687122485835}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.02179786426382509}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021617789532325248}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.03509614368752819}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.008867076040336814}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.047433479205543055}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/dpo_spec.rb b/spec/technical_analysis/indicators/dpo_spec.rb index d7880f3..89d5241 100644 --- a/spec/technical_analysis/indicators/dpo_spec.rb +++ b/spec/technical_analysis/indicators/dpo_spec.rb @@ -10,40 +10,40 @@ output = TechnicalAnalysis::Dpo.calculate(input_data, period: 20, price_key: :close) expected_output = [ - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-31.444000000000017}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-39.16900000000004}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-39.04850000000002}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-43.2405}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-40.02850000000001}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-39.24899999999997}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-31.052999999999997}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-30.723499999999945}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30.462999999999965}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-22.93399999999997}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-29.3245}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-29.007000000000033}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-33.321500000000015}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.836000000000013}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-28.722000000000037}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-26.35200000000006}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-22.884000000000043}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-26.388500000000022}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-25.746500000000054}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-22.48350000000005}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-26.41850000000005}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-29.025999999999982}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-33.053}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-35.0085}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.876499999999993}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.642999999999972}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.498999999999995}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-18.922999999999973}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-17.36949999999996}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31.726499999999987}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-24.407999999999987}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-23.730500000000006}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-15.774999999999977}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-19.607999999999976}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-15.774999999999977} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-23.730500000000006}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-24.407999999999987}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31.726499999999987}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-17.36949999999996}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-18.922999999999973}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.498999999999995}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.642999999999972}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.876499999999993}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-35.0085}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-33.053}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-29.025999999999982}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-26.41850000000005}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-22.48350000000005}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-25.746500000000054}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-26.388500000000022}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-22.884000000000043}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-26.35200000000006}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-28.722000000000037}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.836000000000013}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-33.321500000000015}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-29.007000000000033}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-29.3245}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-22.93399999999997}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30.462999999999965}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-30.723499999999945}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-31.052999999999997}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-39.24899999999997}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-40.02850000000001}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-43.2405}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-39.04850000000002}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-39.16900000000004}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-31.444000000000017} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/dr_spec.rb b/spec/technical_analysis/indicators/dr_spec.rb index 2f46097..3deeab7 100644 --- a/spec/technical_analysis/indicators/dr_spec.rb +++ b/spec/technical_analysis/indicators/dr_spec.rb @@ -10,69 +10,69 @@ output = TechnicalAnalysis::Dr.calculate(input_data, price_key: :close) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.046326089831180806}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.00882787946015906}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.035719281883889176}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021385799828913643}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.022037173352962736}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.004321404456448352}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023373570233735652}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.015230071289695335}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006110072500113972}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009426693859052815}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.034301620796480026}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021897810218978186}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.015923566878980888}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018770226537216828}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004994346023369678}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.026066572902015972}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015352279996344587}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.06633066330663306}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028388278388278287}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010814028473634663}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.030328311331403013}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006954036675398845}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.019281500311765565}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.05037413801535684}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.009991244785497289}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.02824741195442948}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.02467880085653107}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011075701374013924}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.03963209838267967}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.047777897342085596}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011300711944851605}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.025398800769317886}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013523710023797264}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.0021761539342571856}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.038452708907254385}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.0076821045650491415}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005402394876079075}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.03494232276850706}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.043988745806730845}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011149470824608043}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03565705128205121}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.006587928066947413}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.005719339622641484}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.0027871671707289103}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010940272028385545}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.031997660134542305}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.009306260575296044}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.01299255825301926}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.031191666164870235}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.025234632357511222}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.038895619460562525}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.02587407947986453}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.07042157597221266}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006489788127505114}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.00051232788984934}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009665237150355388}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011411182959297772}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.09960739614994929}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.042689359307968244}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022258195062726527}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01698175787728018}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.019063070371121427}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01698175787728018} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022258195062726527}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.042689359307968244}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.09960739614994929}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011411182959297772}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009665237150355388}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.00051232788984934}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006489788127505114}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.07042157597221266}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.02587407947986453}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.038895619460562525}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.025234632357511222}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.031191666164870235}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.01299255825301926}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.009306260575296044}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.031997660134542305}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010940272028385545}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.0027871671707289103}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.005719339622641484}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.006587928066947413}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03565705128205121}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011149470824608043}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.043988745806730845}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.03494232276850706}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005402394876079075}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.0076821045650491415}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.038452708907254385}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.0021761539342571856}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013523710023797264}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.025398800769317886}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011300711944851605}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.047777897342085596}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.03963209838267967}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011075701374013924}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.02467880085653107}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.02824741195442948}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.009991244785497289}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.05037413801535684}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.019281500311765565}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006954036675398845}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.030328311331403013}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010814028473634663}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028388278388278287}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.06633066330663306}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015352279996344587}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.026066572902015972}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004994346023369678}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018770226537216828}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.015923566878980888}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021897810218978186}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.034301620796480026}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009426693859052815}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006110072500113972}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.015230071289695335}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023373570233735652}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.004321404456448352}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.022037173352962736}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021385799828913643}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.035719281883889176}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.00882787946015906}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.046326089831180806}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/eom_spec.rb b/spec/technical_analysis/indicators/eom_spec.rb index 6e9cece..920fe66 100644 --- a/spec/technical_analysis/indicators/eom_spec.rb +++ b/spec/technical_analysis/indicators/eom_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Eom.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb index 7827ebc..071d04a 100644 --- a/spec/technical_analysis/indicators/evm_spec.rb +++ b/spec/technical_analysis/indicators/evm_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Evm.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/fi_spec.rb b/spec/technical_analysis/indicators/fi_spec.rb index 1678990..8358b5b 100644 --- a/spec/technical_analysis/indicators/fi_spec.rb +++ b/spec/technical_analysis/indicators/fi_spec.rb @@ -10,68 +10,68 @@ output = TechnicalAnalysis::Fi.calculate(input_data) expected_output = [ - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-431793575.69999963}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-101043431.20000133}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>302529938.200001}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-143832137.5}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>137964214.49999976}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-21785164.80000018}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-167452577.5999996}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>108156545.69999973}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>38527063.6000001}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>80456833.59999938}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-305539796.7999995}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>136718771.40000024}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-165170950.0}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-185597581.4000001}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>38677205.80000009}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>211373463.60000008}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>177925675.1999992}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-1342026294.4000008}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-389165081.2999991}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>69268889.60000022}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>205742335.19999927}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-36922334.19999948}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-137957395.20000035}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-525207609.0000006}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-90647877.39999989}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-328772056.1999987}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>213312352.5999993}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>76725619.60000016}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-319277709.3999995}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-600986678.4000016}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-6219247.999999646}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-106071625.30000022}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>104063205.60000056}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-15639333.199999813}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>307809724.99999946}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-57717776.19999944}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-38241532.19999996}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>252955247.99999923}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-334478362.4999998}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-84128672.69999996}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-259658176.39999956}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>68552489.99999909}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-44588998.799999945}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>16673099.59999996}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>58745288.49999982}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-222193369.19999996}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-66605646.799999654}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>71894933.69999984}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-246555930.60000032}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-261456813.7999983}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-582537190.0000021}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-144959996.99999917}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>601104008.9999986}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-52641026.99999906}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>3339247.9999993355}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>52094078.90000067}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>6414672.59999923}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-1433110593.199999}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>348561555.4999996}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-18008575.19999913}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>115287987.2000001}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>114556606.19999972}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>115287987.2000001} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-18008575.19999913}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>348561555.4999996}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-1433110593.199999}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>6414672.59999923}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>52094078.90000067}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>3339247.9999993355}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-52641026.99999906}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>601104008.9999986}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-144959996.99999917}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-582537190.0000021}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-261456813.7999983}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-246555930.60000032}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>71894933.69999984}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-66605646.799999654}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-222193369.19999996}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>58745288.49999982}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>16673099.59999996}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-44588998.799999945}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>68552489.99999909}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-259658176.39999956}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-84128672.69999996}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-334478362.4999998}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>252955247.99999923}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-38241532.19999996}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-57717776.19999944}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>307809724.99999946}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-15639333.199999813}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>104063205.60000056}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-106071625.30000022}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-6219247.999999646}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-600986678.4000016}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-319277709.3999995}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>76725619.60000016}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>213312352.5999993}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-328772056.1999987}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-90647877.39999989}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-525207609.0000006}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-137957395.20000035}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-36922334.19999948}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>205742335.19999927}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>69268889.60000022}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-389165081.2999991}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-1342026294.4000008}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>177925675.1999992}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>211373463.60000008}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>38677205.80000009}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-185597581.4000001}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-165170950.0}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>136718771.40000024}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-305539796.7999995}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>80456833.59999938}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>38527063.6000001}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>108156545.69999973}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-167452577.5999996}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-21785164.80000018}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>137964214.49999976}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-143832137.5}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>302529938.200001}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-101043431.20000133}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-431793575.69999963} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb index 8f3507e..3a06890 100644 --- a/spec/technical_analysis/indicators/ichimoku_spec.rb +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -10,41 +10,41 @@ output = TechnicalAnalysis::Ichimoku.calculate(input_data, low_period: 3, medium_period: 10, high_period: 20) expected_output = [ - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:chikou_span=>201.59, :kijun_sen=>198.025, :senkou_span_a=>210.7325, :senkou_span_b=>212.72, :tenkan_sen=>190.44975}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:chikou_span=>203.77, :kijun_sen=>197.555, :senkou_span_a=>208.555, :senkou_span_b=>212.26, :tenkan_sen=>189.97975000000002}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:chikou_span=>209.95, :kijun_sen=>192.815, :senkou_span_a=>207.19, :senkou_span_b=>211.2, :tenkan_sen=>185.23975000000002}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:chikou_span=>208.49, :kijun_sen=>192.815, :senkou_span_a=>208.08499999999998, :senkou_span_b=>211.2, :tenkan_sen=>183.105}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:chikou_span=>204.47, :kijun_sen=>189.055, :senkou_span_a=>208.225, :senkou_span_b=>211.2, :tenkan_sen=>176.785}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:chikou_span=>194.17, :kijun_sen=>185.055, :senkou_span_a=>205.015, :senkou_span_b=>209.01, :tenkan_sen=>175.265}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:chikou_span=>192.23, :kijun_sen=>183.72, :senkou_span_a=>202.81755, :senkou_span_b=>207.84005, :tenkan_sen=>173.4275}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:chikou_span=>186.8, :kijun_sen=>182.61475000000002, :senkou_span_a=>198.51749999999998, :senkou_span_b=>205.07999999999998, :tenkan_sen=>175.77499999999998}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:chikou_span=>191.41, :kijun_sen=>182.61475000000002, :senkou_span_a=>195.6725, :senkou_span_b=>205.07999999999998, :tenkan_sen=>176.84}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:chikou_span=>193.53, :kijun_sen=>182.61475000000002, :senkou_span_a=>194.237375, :senkou_span_b=>205.07999999999998, :tenkan_sen=>178.865}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:chikou_span=>185.86, :kijun_sen=>180.48, :senkou_span_a=>193.76737500000002, :senkou_span_b=>204.61, :tenkan_sen=>180.985}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:chikou_span=>176.98, :kijun_sen=>177.6, :senkou_span_a=>189.027375, :senkou_span_b=>199.87, :tenkan_sen=>180.60500000000002}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:chikou_span=>176.78, :kijun_sen=>177.6, :senkou_span_a=>187.95999999999998, :senkou_span_b=>198.935, :tenkan_sen=>177.68}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:chikou_span=>172.29, :kijun_sen=>176.62, :senkou_span_a=>182.92000000000002, :senkou_span_b=>197.23000000000002, :tenkan_sen=>175.34495}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:chikou_span=>174.62, :kijun_sen=>174.135, :senkou_span_a=>180.16, :senkou_span_b=>196.31, :tenkan_sen=>169.055}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:chikou_span=>174.24, :kijun_sen=>174.135, :senkou_span_a=>178.57375000000002, :senkou_span_b=>196.31, :tenkan_sen=>168.91000000000003}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:chikou_span=>180.94, :kijun_sen=>174.135, :senkou_span_a=>179.194875, :senkou_span_b=>196.31, :tenkan_sen=>167.625}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:chikou_span=>179.55, :kijun_sen=>174.135, :senkou_span_a=>179.727375, :senkou_span_b=>196.31, :tenkan_sen=>169.785}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:chikou_span=>178.58, :kijun_sen=>174.135, :senkou_span_a=>180.739875, :senkou_span_b=>191.95499999999998, :tenkan_sen=>168.925}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:chikou_span=>184.82, :kijun_sen=>173.83499999999998, :senkou_span_a=>180.73250000000002, :senkou_span_b=>190.19, :tenkan_sen=>167.64999999999998}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:chikou_span=>176.69, :kijun_sen=>172.55995000000001, :senkou_span_a=>179.10250000000002, :senkou_span_b=>190.19, :tenkan_sen=>165.905}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:chikou_span=>174.72, :kijun_sen=>166.935, :senkou_span_a=>177.64, :senkou_span_b=>190.19, :tenkan_sen=>163.72}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:chikou_span=>168.49, :kijun_sen=>164.895, :senkou_span_a=>175.98247500000002, :senkou_span_b=>189.21, :tenkan_sen=>161.41500000000002}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:chikou_span=>169.6, :kijun_sen=>161.1, :senkou_span_a=>171.595, :senkou_span_b=>184.67000000000002, :tenkan_sen=>158.54}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:chikou_span=>168.63, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.5225, :senkou_span_b=>181.59, :tenkan_sen=>154.35000000000002}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:chikou_span=>169.1, :kijun_sen=>159.57999999999998, :senkou_span_a=>170.88, :senkou_span_b=>180.255, :tenkan_sen=>152.375}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:chikou_span=>170.95, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.95999999999998, :senkou_span_b=>179.14975, :tenkan_sen=>151.91}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:chikou_span=>165.48, :kijun_sen=>157.835, :senkou_span_a=>171.53, :senkou_span_b=>179.14975, :tenkan_sen=>152.62}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:chikou_span=>163.94, :kijun_sen=>157.47, :senkou_span_a=>170.74249999999998, :senkou_span_b=>178.84975, :tenkan_sen=>154.715}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:chikou_span=>166.07, :kijun_sen=>157.06, :senkou_span_a=>169.23247500000002, :senkou_span_b=>176.71499999999997, :tenkan_sen=>156.79500000000002}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:chikou_span=>160.89, :kijun_sen=>154.725, :senkou_span_a=>165.3275, :senkou_span_b=>172.015, :tenkan_sen=>150.68}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:chikou_span=>156.83, :kijun_sen=>152.055, :senkou_span_a=>163.15500000000003, :senkou_span_b=>170.12, :tenkan_sen=>150.425}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:chikou_span=>150.73, :kijun_sen=>150.68, :senkou_span_a=>159.82, :senkou_span_b=>167.285, :tenkan_sen=>145.41500000000002}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:chikou_span=>146.83, :kijun_sen=>150.68, :senkou_span_a=>156.965, :senkou_span_b=>165.765, :tenkan_sen=>147.81}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:chikou_span=>150.73, :kijun_sen=>150.68, :senkou_span_a=>159.82, :senkou_span_b=>167.285, :tenkan_sen=>145.41500000000002}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:chikou_span=>156.83, :kijun_sen=>152.055, :senkou_span_a=>163.15500000000003, :senkou_span_b=>170.12, :tenkan_sen=>150.425}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:chikou_span=>160.89, :kijun_sen=>154.725, :senkou_span_a=>165.3275, :senkou_span_b=>172.015, :tenkan_sen=>150.68}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:chikou_span=>166.07, :kijun_sen=>157.06, :senkou_span_a=>169.23247500000002, :senkou_span_b=>176.71499999999997, :tenkan_sen=>156.79500000000002}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:chikou_span=>163.94, :kijun_sen=>157.47, :senkou_span_a=>170.74249999999998, :senkou_span_b=>178.84975, :tenkan_sen=>154.715}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:chikou_span=>165.48, :kijun_sen=>157.835, :senkou_span_a=>171.53, :senkou_span_b=>179.14975, :tenkan_sen=>152.62}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:chikou_span=>170.95, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.95999999999998, :senkou_span_b=>179.14975, :tenkan_sen=>151.91}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:chikou_span=>169.1, :kijun_sen=>159.57999999999998, :senkou_span_a=>170.88, :senkou_span_b=>180.255, :tenkan_sen=>152.375}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:chikou_span=>168.63, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.5225, :senkou_span_b=>181.59, :tenkan_sen=>154.35000000000002}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:chikou_span=>169.6, :kijun_sen=>161.1, :senkou_span_a=>171.595, :senkou_span_b=>184.67000000000002, :tenkan_sen=>158.54}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:chikou_span=>168.49, :kijun_sen=>164.895, :senkou_span_a=>175.98247500000002, :senkou_span_b=>189.21, :tenkan_sen=>161.41500000000002}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:chikou_span=>174.72, :kijun_sen=>166.935, :senkou_span_a=>177.64, :senkou_span_b=>190.19, :tenkan_sen=>163.72}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:chikou_span=>176.69, :kijun_sen=>172.55995000000001, :senkou_span_a=>179.10250000000002, :senkou_span_b=>190.19, :tenkan_sen=>165.905}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:chikou_span=>184.82, :kijun_sen=>173.83499999999998, :senkou_span_a=>180.73250000000002, :senkou_span_b=>190.19, :tenkan_sen=>167.64999999999998}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:chikou_span=>178.58, :kijun_sen=>174.135, :senkou_span_a=>180.739875, :senkou_span_b=>191.95499999999998, :tenkan_sen=>168.925}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:chikou_span=>179.55, :kijun_sen=>174.135, :senkou_span_a=>179.727375, :senkou_span_b=>196.31, :tenkan_sen=>169.785}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:chikou_span=>180.94, :kijun_sen=>174.135, :senkou_span_a=>179.194875, :senkou_span_b=>196.31, :tenkan_sen=>167.625}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:chikou_span=>174.24, :kijun_sen=>174.135, :senkou_span_a=>178.57375000000002, :senkou_span_b=>196.31, :tenkan_sen=>168.91000000000003}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:chikou_span=>174.62, :kijun_sen=>174.135, :senkou_span_a=>180.16, :senkou_span_b=>196.31, :tenkan_sen=>169.055}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:chikou_span=>172.29, :kijun_sen=>176.62, :senkou_span_a=>182.92000000000002, :senkou_span_b=>197.23000000000002, :tenkan_sen=>175.34495}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:chikou_span=>176.78, :kijun_sen=>177.6, :senkou_span_a=>187.95999999999998, :senkou_span_b=>198.935, :tenkan_sen=>177.68}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:chikou_span=>176.98, :kijun_sen=>177.6, :senkou_span_a=>189.027375, :senkou_span_b=>199.87, :tenkan_sen=>180.60500000000002}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:chikou_span=>185.86, :kijun_sen=>180.48, :senkou_span_a=>193.76737500000002, :senkou_span_b=>204.61, :tenkan_sen=>180.985}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:chikou_span=>193.53, :kijun_sen=>182.61475000000002, :senkou_span_a=>194.237375, :senkou_span_b=>205.07999999999998, :tenkan_sen=>178.865}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:chikou_span=>191.41, :kijun_sen=>182.61475000000002, :senkou_span_a=>195.6725, :senkou_span_b=>205.07999999999998, :tenkan_sen=>176.84}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:chikou_span=>186.8, :kijun_sen=>182.61475000000002, :senkou_span_a=>198.51749999999998, :senkou_span_b=>205.07999999999998, :tenkan_sen=>175.77499999999998}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:chikou_span=>192.23, :kijun_sen=>183.72, :senkou_span_a=>202.81755, :senkou_span_b=>207.84005, :tenkan_sen=>173.4275}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:chikou_span=>194.17, :kijun_sen=>185.055, :senkou_span_a=>205.015, :senkou_span_b=>209.01, :tenkan_sen=>175.265}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:chikou_span=>204.47, :kijun_sen=>189.055, :senkou_span_a=>208.225, :senkou_span_b=>211.2, :tenkan_sen=>176.785}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:chikou_span=>208.49, :kijun_sen=>192.815, :senkou_span_a=>208.08499999999998, :senkou_span_b=>211.2, :tenkan_sen=>183.105}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:chikou_span=>209.95, :kijun_sen=>192.815, :senkou_span_a=>207.19, :senkou_span_b=>211.2, :tenkan_sen=>185.23975000000002}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:chikou_span=>203.77, :kijun_sen=>197.555, :senkou_span_a=>208.555, :senkou_span_b=>212.26, :tenkan_sen=>189.97975000000002}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:chikou_span=>201.59, :kijun_sen=>198.025, :senkou_span_a=>210.7325, :senkou_span_b=>212.72, :tenkan_sen=>190.44975}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/kc_spec.rb b/spec/technical_analysis/indicators/kc_spec.rb index 4bc1f8d..cd91bc7 100644 --- a/spec/technical_analysis/indicators/kc_spec.rb +++ b/spec/technical_analysis/indicators/kc_spec.rb @@ -10,60 +10,60 @@ output = TechnicalAnalysis::Kc.calculate(input_data, period: 10) expected_output = [ - {:date_time=>"2018-10-22T00:00:00.000Z", :value=> {:lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667}}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=> {:lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664}}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=> {:lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333}}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=> {:lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004}}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=> {:lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667}}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005}}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>146.74034, :middle_band=>151.57433, :upper_band=>156.40832}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667}}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495}}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005}}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=> {:lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667}}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=> {:lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004}}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=> {:lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333}}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=> {:lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664}}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=> {:lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/kst_spec.rb b/spec/technical_analysis/indicators/kst_spec.rb index 18b50e2..9a98037 100644 --- a/spec/technical_analysis/indicators/kst_spec.rb +++ b/spec/technical_analysis/indicators/kst_spec.rb @@ -10,26 +10,26 @@ output = TechnicalAnalysis::Kst.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close) expected_output = [ - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-150.14198896419614}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-146.67417088368043}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-143.06704590371226}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-141.6235541026754}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-140.69442915235626}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-141.36803679622636}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-141.34365936138443}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-143.4025404878081}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-145.9029270207904}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-150.769274028613}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-151.25248412993977}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-152.69243922992774}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-154.278039839607}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-152.43337072156913}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-150.77021075475108}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-157.0260814891967}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-157.83675223915662}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-155.71040741442587}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-140.9140022298261}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-148.9261153101682}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-140.9140022298261} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-155.71040741442587}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-157.83675223915662}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-157.0260814891967}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-150.77021075475108}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-152.43337072156913}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-154.278039839607}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-152.69243922992774}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-151.25248412993977}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-150.769274028613}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-145.9029270207904}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-143.4025404878081}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-141.34365936138443}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-141.36803679622636}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-140.69442915235626}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-141.6235541026754}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-143.06704590371226}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-146.67417088368043}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-150.14198896419614} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb index bbffa99..529a55e 100644 --- a/spec/technical_analysis/indicators/macd_spec.rb +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -10,36 +10,36 @@ output = TechnicalAnalysis::Macd.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close) expected_output = [ - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:macd_histogram=>0.4770591535283888, :macd_line=>-8.745173952069024, :signal_line=>-9.222233105597413}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/mfi_spec.rb b/spec/technical_analysis/indicators/mfi_spec.rb index 138b6d3..8aebc5f 100644 --- a/spec/technical_analysis/indicators/mfi_spec.rb +++ b/spec/technical_analysis/indicators/mfi_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Mfi.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>35.973926377719295}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>36.38768375444253}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>45.214622261116865}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>46.69168911629936}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>41.95906812943111}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78216906343063}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>35.50426811855657}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40.83081970751587}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>39.93886476277229}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>34.82129345577579}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>34.42914208336833}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>34.34229761188338}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>28.384945303826555}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>35.21136683265594}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>41.22749344358184}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>41.216526023725}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>33.960148214906965}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>26.562703378271138}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.0162422598642}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>31.547361595662196}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>31.964707056845796}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>32.76065853310956}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>34.06816082393442}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>34.05798943239071}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>41.56028762200471}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>42.20999531156955}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>43.83608665179891}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>36.043235982173}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>28.368262151706787}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>35.65846689890073}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43.77747404533765}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>49.219385053554596}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>47.94902504034211}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>48.23034273673764}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>47.447534147092476}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>39.506183778454634}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>31.23926122664477}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>29.111701049682864}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.795547568232564}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>30.54886108664553}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>37.56125308902594}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>43.66248537462054}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>50.84666407662511}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>44.40322811326429}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>36.12141791144509}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>37.81171947764313}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>44.40424662233335}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>50.72343663578981}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>50.1757147722236}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>50.72343663578981} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>44.40424662233335}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>37.81171947764313}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>36.12141791144509}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>44.40322811326429}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>50.84666407662511}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>43.66248537462054}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>37.56125308902594}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>30.54886108664553}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.795547568232564}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>29.111701049682864}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>31.23926122664477}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>39.506183778454634}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>47.447534147092476}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>48.23034273673764}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>47.94902504034211}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>49.219385053554596}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43.77747404533765}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>35.65846689890073}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>28.368262151706787}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>36.043235982173}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>43.83608665179891}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>42.20999531156955}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>41.56028762200471}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>34.05798943239071}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>34.06816082393442}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>32.76065853310956}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>31.964707056845796}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>31.547361595662196}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.0162422598642}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>26.562703378271138}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>33.960148214906965}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>41.216526023725}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>41.22749344358184}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>35.21136683265594}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>28.384945303826555}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>34.34229761188338}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>34.42914208336833}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>34.82129345577579}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>39.93886476277229}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40.83081970751587}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>35.50426811855657}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78216906343063}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>41.95906812943111}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>46.69168911629936}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>45.214622261116865}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>36.38768375444253}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>35.973926377719295} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/mi_spec.rb b/spec/technical_analysis/indicators/mi_spec.rb index 3eb590a..9f908f6 100644 --- a/spec/technical_analysis/indicators/mi_spec.rb +++ b/spec/technical_analysis/indicators/mi_spec.rb @@ -10,29 +10,29 @@ output = TechnicalAnalysis::Mi.calculate(input_data, ema_period: 9, sum_period: 25) expected_output = [ - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>23.82917406071097}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>23.8163614080134}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>23.890966368346767}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>23.89261610689666}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>23.835760161850434}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>23.82241708019551}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>23.792012619835983}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>23.879826345759078}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>23.94958830559542}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>24.12156756268421}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>24.303447406952383}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.454674020826847}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.564590708470064}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>24.791003528125515}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>24.964776002066408}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>25.020764664334674}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>25.03284918462693}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>25.04245599370965}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>25.018142841959207}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>25.026285600546654}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>24.924292786436485}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>24.77520633216394}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>24.80084030980544}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>24.77520633216394} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>24.924292786436485}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>25.026285600546654}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>25.018142841959207}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>25.04245599370965}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>25.03284918462693}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>25.020764664334674}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>24.964776002066408}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>24.791003528125515}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.564590708470064}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.454674020826847}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>24.303447406952383}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>24.12156756268421}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>23.94958830559542}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>23.879826345759078}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>23.792012619835983}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>23.82241708019551}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>23.835760161850434}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>23.89261610689666}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>23.890966368346767}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>23.8163614080134}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>23.82917406071097} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/nvi_spec.rb b/spec/technical_analysis/indicators/nvi_spec.rb index 93a9de7..e792cd9 100644 --- a/spec/technical_analysis/indicators/nvi_spec.rb +++ b/spec/technical_analysis/indicators/nvi_spec.rb @@ -10,69 +10,69 @@ output = TechnicalAnalysis::Nvi.calculate(input_data) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>1000.0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>1000.0}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>1000.0}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>1003.5719281883889}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>1001.4333482054976}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>1003.6370655407939}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>1006.0057133670583}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>1006.0057133670583}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>1004.1286907133366}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>1001.7892974768458}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>1002.8707003242093}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>1002.8707003242093}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>1001.1761721781198}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>1001.1761721781198}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>1003.6440522637729}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>1004.6386152817257}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>1002.0987352047939}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>1002.0987352047939}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>1001.8811198113682}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>1001.8811198113682}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>1001.1129093548633}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>997.0069647390503}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>997.0069647390503}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>996.4350307767862}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>996.713747493859}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>996.519622574013}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>996.519622574013}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>995.8706437612625}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>995.9218765502475}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>1001.1573361960799}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>1000.9347542454526}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>1002.8410612825647}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>1002.8410612825647}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>1002.8410612825647} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>1000.9347542454526}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>1001.1573361960799}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>996.888400265283}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>995.9218765502475}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>995.8706437612625}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>996.519622574013}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>996.519622574013}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>999.1070305219995}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>997.8077746966976}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>996.713747493859}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>996.4350307767862}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>997.0069647390503}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>997.0069647390503}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>1000.5726698672554}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>1001.1129093548633}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>1001.8811198113682}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>1001.8811198113682}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>1002.0987352047939}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>1002.0987352047939}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>1004.6386152817257}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>1004.7516224011742}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>1003.6440522637729}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>1001.1761721781198}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>1001.1761721781198}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>1002.1752966566695}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>1002.8707003242093}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>1002.8707003242093}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>1001.7892974768458}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>1004.6281253156736}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>1004.1286907133366}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>1006.0057133670583}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>1006.0057133670583}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>1003.8159323451605}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>1003.2049250951491}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>1003.6370655407939}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>1001.4333482054976}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>1003.5719281883889}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>1000.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>1000.0}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>1000.0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb index a54f3e3..3b2ffe5 100644 --- a/spec/technical_analysis/indicators/obv_mean_spec.rb +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -10,59 +10,59 @@ output = TechnicalAnalysis::ObvMean.calculate(input_data, period: 10) expected_output = [ - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-65836555.0}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-66801824.0}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-59574127.0}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-61015077.0}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-63999351.0}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-66215087.0}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-62359854.0}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-49970286.0}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-49972807.0}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-59457699.0}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-69633236.0}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-72480397.0}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-80759219.0}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-87750647.0}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-95269809.0}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-111110335.0}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-136807276.0}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-163172458.0}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-176813851.0}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-188010709.0}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-209152907.0}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-236733893.0}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-264148349.0}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-283664797.0}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-302197756.0}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-311463969.0}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-318827806.0}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-334761235.0}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-350260027.0}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-365710262.0}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-378663120.0}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-392674222.0}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-398147027.0}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-412682868.0}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-419555627.0}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-427847140.0}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-436048331.0}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-444632138.0}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-453894366.0}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-463802236.0}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-475879438.0}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-493338562.0}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-520690509.0}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-537632267.0}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-563282378.0}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-587933850.0}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-605073347.0}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-614324095.0}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-636060876.0}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-647295525.0}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-657547495.0}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-642606913.0}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-654187384.0}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-642606913.0} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-657547495.0}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-647295525.0}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-636060876.0}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-614324095.0}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-605073347.0}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-587933850.0}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-563282378.0}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-537632267.0}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-520690509.0}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-493338562.0}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-475879438.0}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-463802236.0}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-453894366.0}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-444632138.0}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-436048331.0}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-427847140.0}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-419555627.0}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-412682868.0}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-398147027.0}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-392674222.0}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-378663120.0}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-365710262.0}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-350260027.0}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-334761235.0}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-318827806.0}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-311463969.0}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-302197756.0}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-283664797.0}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-264148349.0}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-236733893.0}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-209152907.0}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-188010709.0}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-176813851.0}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-163172458.0}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-136807276.0}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-111110335.0}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-95269809.0}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-87750647.0}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-80759219.0}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-72480397.0}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-69633236.0}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-59457699.0}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-49972807.0}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-49970286.0}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-62359854.0}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-66215087.0}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-63999351.0}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-61015077.0}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-59574127.0}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-66801824.0}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-65836555.0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/obv_spec.rb b/spec/technical_analysis/indicators/obv_spec.rb index 088e255..98ad833 100644 --- a/spec/technical_analysis/indicators/obv_spec.rb +++ b/spec/technical_analysis/indicators/obv_spec.rb @@ -10,69 +10,69 @@ output = TechnicalAnalysis::Obv.calculate(input_data) expected_output = [ - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-41084070}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-93986390}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-54491620}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-84772070}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-55969520}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-78662400}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-111051680}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-78177350}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-49425810}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-10744640}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-50736760}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-21709420}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-68901120}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-114614810}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-78126880}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-40110070}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>12844000}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-78202560}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-144274730}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-112500010}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-79208370}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-104497640}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-138815400}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-189806430}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-236532140}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-297079480}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-250807820}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-214616490}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-256243310}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-323921990}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-355018230}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-378642200}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-333979880}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-375136020}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-329194270}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-370717850}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-410142110}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-369604410}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-410745660}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-453450570}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-495129250}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-433370250}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-479338290}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-443863610}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-412109400}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-452729760}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-495980180}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-462226690}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-509824360}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-574222590}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-669720490}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-706889720}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-648755870}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-700364720}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-658624120}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-624124730}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-588487660}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-679594500}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-622170850}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-676742290}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-591085010}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-636119380}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-591085010} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-676742290}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-622170850}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-679594500}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-588487660}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-624124730}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-658624120}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-700364720}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-648755870}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-706889720}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-669720490}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-574222590}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-509824360}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-462226690}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-495980180}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-452729760}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-412109400}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-443863610}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-479338290}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-433370250}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-495129250}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-453450570}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-410745660}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-369604410}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-410142110}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-370717850}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-329194270}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-375136020}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-333979880}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-378642200}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-355018230}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-323921990}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-256243310}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-214616490}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-250807820}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-297079480}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-236532140}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-189806430}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-138815400}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-104497640}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-79208370}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-112500010}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-144274730}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-78202560}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>12844000}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-40110070}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-78126880}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-114614810}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-68901120}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-21709420}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-50736760}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-10744640}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-49425810}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-78177350}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-111051680}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-78662400}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-55969520}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-84772070}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-54491620}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-93986390}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-41084070}, + {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb index 66e18e8..c4443fc 100644 --- a/spec/technical_analysis/indicators/rsi_spec.rb +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Rsi.calculate(input_data, period: 14, price_key: :close) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>38.27160493827161}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>39.38109368376431}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>44.96841382331871}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>48.08268788472883}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>37.93941116682432}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78189708111985}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>36.875893042068746}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>42.51108193242363}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>41.56699725744853}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>38.99885805229995}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>33.31877385045367}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>32.36268849740294}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>29.78632377839773}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>34.550163030510646}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>36.677863857193564}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>32.554453236286506}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>28.552282046348225}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>28.467396310763007}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>26.558433878585916}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>29.211255846774762}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>29.027101402280678}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>36.61457624117541}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>35.760430191057694}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>35.1442970032345}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>42.06016450933706}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>36.58615110748291}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>35.38441991619841}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>31.82436379692355}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>33.115551932880564}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>32.53565170863392}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>33.146531878947414}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>35.61772436774288}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>31.866930881658718}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>30.880956115136144}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>33.926041361905774}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>30.416532991054595}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>27.973957664061984}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.757134961511937}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.94077952430888}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>36.28727515078207}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>35.63166885267985}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>35.7297472286003}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>37.66054013673465}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>37.90003559360193}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>27.835833051062522}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>35.00790948034705}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>34.80538400125879}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>41.01572095202713}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>38.100858593859655}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>41.01572095202713} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>34.80538400125879}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>35.00790948034705}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>27.835833051062522}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>37.90003559360193}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>37.66054013673465}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>35.7297472286003}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>35.63166885267985}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>36.28727515078207}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.94077952430888}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.757134961511937}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>27.973957664061984}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>30.416532991054595}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>33.926041361905774}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>30.880956115136144}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>31.866930881658718}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>35.61772436774288}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>33.146531878947414}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>32.53565170863392}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>33.115551932880564}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>31.82436379692355}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>35.38441991619841}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>36.58615110748291}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>42.06016450933706}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>35.1442970032345}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>35.760430191057694}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>36.61457624117541}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>29.027101402280678}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>29.211255846774762}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>26.558433878585916}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>28.467396310763007}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>28.552282046348225}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>32.554453236286506}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>36.677863857193564}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>34.550163030510646}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>29.78632377839773}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>32.36268849740294}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>33.31877385045367}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>38.99885805229995}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>41.56699725744853}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>42.51108193242363}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>36.875893042068746}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78189708111985}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>37.93941116682432}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>48.08268788472883}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>44.96841382331871}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>39.38109368376431}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>38.27160493827161} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index c57b417..8bb4c68 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -10,65 +10,65 @@ output = TechnicalAnalysis::Sma.calculate(input_data, period: 5, price_key: :close) expected_output = [ - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>149.41}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/sr_spec.rb b/spec/technical_analysis/indicators/sr_spec.rb index 5451ea9..bec09d8 100644 --- a/spec/technical_analysis/indicators/sr_spec.rb +++ b/spec/technical_analysis/indicators/sr_spec.rb @@ -10,54 +10,54 @@ output = TechnicalAnalysis::Sr.calculate(input_data, period: 14, signal_period: 3) expected_output = [ - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>{:sr=>39.746416758544726, :sr_signal=>32.241290132123396}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>{:sr=>70.39691289966935, :sr_signal=>46.83290323914804}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>{:sr=>88.91951488423378, :sr_signal=>66.35428151414929}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>{:sr=>10.904255319148854, :sr_signal=>56.740227701017325}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:sr=>13.123561013046874, :sr_signal=>37.649110405476506}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:sr=>21.48887183422879, :sr_signal=>15.172229388808171}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:sr=>45.203376822716805, :sr_signal=>26.605269889997487}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:sr=>39.60092095165012, :sr_signal=>35.431056536198575}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:sr=>24.174980813507332, :sr_signal=>36.326426195958085}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:sr=>1.2483574244415094, :sr_signal=>21.674753063199656}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:sr=>2.5231398354572394, :sr_signal=>9.31549269113536}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:sr=>2.388141641504267, :sr_signal=>2.0532129671343387}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:sr=>15.04254735108424, :sr_signal=>6.651276276015249}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:sr=>20.86192698325554, :sr_signal=>12.764205325281347}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:sr=>2.32807064490234, :sr_signal=>12.744181659747374}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:sr=>3.137673425827104, :sr_signal=>8.775890351328327}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:sr=>3.329837441006842, :sr_signal=>2.931860503912096}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:sr=>0.49973698053655363, :sr_signal=>2.3224159491234997}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:sr=>10.938283993978956, :sr_signal=>4.922619471840783}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:sr=>9.984947315604659, :sr_signal=>7.140989430040055}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:sr=>26.79377822378325, :sr_signal=>15.905669844455621}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:sr=>25.986013986014044, :sr_signal=>20.92157984180065}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:sr=>28.117607299763502, :sr_signal=>26.965799836520265}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:sr=>54.0861812778603, :sr_signal=>36.063267521212616}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:sr=>26.022380056253674, :sr_signal=>36.07538954462583}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:sr=>18.049737955037553, :sr_signal=>32.719433096383845}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:sr=>0.712424304917594, :sr_signal=>14.928180772069608}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:sr=>22.908293752283477, :sr_signal=>13.89015200407954}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:sr=>24.525682554372914, :sr_signal=>16.048800203857994}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:sr=>26.700601573345605, :sr_signal=>24.711525960000667}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:sr=>35.26145303100408, :sr_signal=>28.8292457195742}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:sr=>9.94909763998139, :sr_signal=>23.970384081443694}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:sr=>5.447996398018944, :sr_signal=>16.886182356334803}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:sr=>15.038271049077, :sr_signal=>10.145121695692445}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:sr=>6.963249516440942, :sr_signal=>9.149838987845628}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:sr=>5.161943319838063, :sr_signal=>9.054487961785336}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:sr=>3.1152647975077716, :sr_signal=>5.080152544595593}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:sr=>0.6703929340585003, :sr_signal=>2.9825336838014445}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:sr=>37.531039375665074, :sr_signal=>13.772232369077116}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:sr=>34.2652329749104, :sr_signal=>24.155555094877986}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:sr=>37.105465742879105, :sr_signal=>36.300579364484854}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:sr=>42.917628945342614, :sr_signal=>38.09610922104404}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:sr=>43.61046959199379, :sr_signal=>41.21118809340517}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:sr=>0.6215243702976702, :sr_signal=>29.04987430254469}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:sr=>23.1166912850812, :sr_signal=>22.449561749124218}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:sr=>22.50474383301711, :sr_signal=>15.414319829465327}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:sr=>44.44007858546172, :sr_signal=>33.739408752366685}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:sr=>34.27340383862123, :sr_signal=>26.631612985573174}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:sr=>44.44007858546172, :sr_signal=>33.739408752366685}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:sr=>22.50474383301711, :sr_signal=>15.414319829465327}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:sr=>23.1166912850812, :sr_signal=>22.449561749124218}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:sr=>0.6215243702976702, :sr_signal=>29.04987430254469}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:sr=>43.61046959199379, :sr_signal=>41.21118809340517}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:sr=>42.917628945342614, :sr_signal=>38.09610922104404}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:sr=>37.105465742879105, :sr_signal=>36.300579364484854}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:sr=>34.2652329749104, :sr_signal=>24.155555094877986}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:sr=>37.531039375665074, :sr_signal=>13.772232369077116}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:sr=>0.6703929340585003, :sr_signal=>2.9825336838014445}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:sr=>3.1152647975077716, :sr_signal=>5.080152544595593}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:sr=>5.161943319838063, :sr_signal=>9.054487961785336}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:sr=>6.963249516440942, :sr_signal=>9.149838987845628}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:sr=>15.038271049077, :sr_signal=>10.145121695692445}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:sr=>5.447996398018944, :sr_signal=>16.886182356334803}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:sr=>9.94909763998139, :sr_signal=>23.970384081443694}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:sr=>35.26145303100408, :sr_signal=>28.8292457195742}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:sr=>26.700601573345605, :sr_signal=>24.711525960000667}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:sr=>24.525682554372914, :sr_signal=>16.048800203857994}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:sr=>22.908293752283477, :sr_signal=>13.89015200407954}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:sr=>0.712424304917594, :sr_signal=>14.928180772069608}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:sr=>18.049737955037553, :sr_signal=>32.719433096383845}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:sr=>26.022380056253674, :sr_signal=>36.07538954462583}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:sr=>54.0861812778603, :sr_signal=>36.063267521212616}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:sr=>28.117607299763502, :sr_signal=>26.965799836520265}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:sr=>25.986013986014044, :sr_signal=>20.92157984180065}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:sr=>26.79377822378325, :sr_signal=>15.905669844455621}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:sr=>9.984947315604659, :sr_signal=>7.140989430040055}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:sr=>10.938283993978956, :sr_signal=>4.922619471840783}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:sr=>0.49973698053655363, :sr_signal=>2.3224159491234997}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:sr=>3.329837441006842, :sr_signal=>2.931860503912096}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:sr=>3.137673425827104, :sr_signal=>8.775890351328327}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:sr=>2.32807064490234, :sr_signal=>12.744181659747374}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:sr=>20.86192698325554, :sr_signal=>12.764205325281347}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:sr=>15.04254735108424, :sr_signal=>6.651276276015249}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:sr=>2.388141641504267, :sr_signal=>2.0532129671343387}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:sr=>2.5231398354572394, :sr_signal=>9.31549269113536}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:sr=>1.2483574244415094, :sr_signal=>21.674753063199656}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:sr=>24.174980813507332, :sr_signal=>36.326426195958085}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:sr=>39.60092095165012, :sr_signal=>35.431056536198575}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:sr=>45.203376822716805, :sr_signal=>26.605269889997487}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:sr=>21.48887183422879, :sr_signal=>15.172229388808171}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:sr=>13.123561013046874, :sr_signal=>37.649110405476506}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>{:sr=>10.904255319148854, :sr_signal=>56.740227701017325}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>{:sr=>88.91951488423378, :sr_signal=>66.35428151414929}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>{:sr=>70.39691289966935, :sr_signal=>46.83290323914804}}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>{:sr=>39.746416758544726, :sr_signal=>32.241290132123396}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/trix_spec.rb b/spec/technical_analysis/indicators/trix_spec.rb index e6220e1..ae7a83a 100644 --- a/spec/technical_analysis/indicators/trix_spec.rb +++ b/spec/technical_analysis/indicators/trix_spec.rb @@ -10,26 +10,26 @@ output = TechnicalAnalysis::Trix.calculate(input_data, period: 15, price_key: :close) expected_output = [ - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.007673381215454718}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.007622995995719011}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.007537530463588133}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.007473061875390961}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.007428539823046746}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.007365504921638632}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.007332615495168546}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.00735126292321306}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.007455715388896471}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.007643867247128558}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.00776162437514068}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.007824502562605692}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.007833433859114468}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.007775594696883065}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.007658933006361239}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.007665196848424279}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.00767662212545961}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.007682172922749195}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.007522826289174942}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.007639218329257057}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.007522826289174942} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.007682172922749195}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.00767662212545961}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.007665196848424279}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.007658933006361239}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.007775594696883065}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.007833433859114468}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.007824502562605692}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.00776162437514068}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.007643867247128558}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.007455715388896471}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.00735126292321306}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.007332615495168546}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.007365504921638632}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.007428539823046746}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.007473061875390961}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.007537530463588133}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.007622995995719011}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.007673381215454718} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/tsi_spec.rb b/spec/technical_analysis/indicators/tsi_spec.rb index bef3452..949b4f7 100644 --- a/spec/technical_analysis/indicators/tsi_spec.rb +++ b/spec/technical_analysis/indicators/tsi_spec.rb @@ -10,32 +10,32 @@ output = TechnicalAnalysis::Tsi.calculate(input_data, low_period: 13, high_period: 25, price_key: :close) expected_output = [ - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-32.212798598181024}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-29.524570107700253}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28.752945178257534}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-28.4796578607378}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-29.357900955250976}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.704744795960114}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-30.15935663446155}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-30.375476807689427}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-29.91401235092671}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-30.569488217596724}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-31.403055885745307}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-31.30170501401141}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-32.23640227177938}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-33.78946079860395}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-36.202827241203856}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-38.83883734905748}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-36.802531445786066}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-35.41195667338275}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-34.28080772951784}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-32.785927300024994}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-31.495178028566524}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-33.579027007940994}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-32.874679857827935}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-32.39480993311267}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-28.91017661103889}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-30.97413963420104}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-28.91017661103889} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-32.39480993311267}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-32.874679857827935}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-33.579027007940994}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-31.495178028566524}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-32.785927300024994}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-34.28080772951784}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-35.41195667338275}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-36.802531445786066}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-38.83883734905748}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-36.202827241203856}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-33.78946079860395}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-32.23640227177938}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-31.30170501401141}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-31.403055885745307}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-30.569488217596724}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-29.91401235092671}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-30.375476807689427}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-30.15935663446155}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.704744795960114}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-29.357900955250976}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-28.4796578607378}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28.752945178257534}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-29.524570107700253}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-32.212798598181024} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/uo_spec.rb b/spec/technical_analysis/indicators/uo_spec.rb index ebe644d..f910452 100644 --- a/spec/technical_analysis/indicators/uo_spec.rb +++ b/spec/technical_analysis/indicators/uo_spec.rb @@ -10,41 +10,41 @@ output = TechnicalAnalysis::Uo.calculate(input_data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) expected_output = [ - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>37.48593642184523}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>33.50557345611348}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>29.938582222468735}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>30.12209085444982}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.31628731487427}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>37.129780535443615}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>36.448196445521205}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>39.6100967511459}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>42.75825214517756}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>48.76091038333585}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>58.63742128493122}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>54.53131218526129}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>54.531561679403225}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>46.3795568325064}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>46.78620949538559}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>47.39018769748099}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>46.56343334880161}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>42.5926187322538}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43.99139965247388}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>38.091246151228205}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>42.6017793901735}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>31.693410049073588}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>30.219780692869403}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>28.31825074884628}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.01487703769969}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>38.89197235556109}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>44.80062908207362}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>44.736408028234784}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46.12625788315007}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>51.63477005783912}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>43.660461129633255}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>50.726610056055335}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>46.58165158841807}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>47.28872762629681}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>44.828908983561035}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>47.28872762629681} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>46.58165158841807}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>50.726610056055335}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>43.660461129633255}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>51.63477005783912}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46.12625788315007}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>44.736408028234784}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>44.80062908207362}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>38.89197235556109}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.01487703769969}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>28.31825074884628}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>30.219780692869403}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>31.693410049073588}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>42.6017793901735}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>38.091246151228205}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43.99139965247388}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>42.5926187322538}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>46.56343334880161}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>47.39018769748099}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>46.78620949538559}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>46.3795568325064}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>54.531561679403225}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>54.53131218526129}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>58.63742128493122}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>48.76091038333585}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>42.75825214517756}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>39.6100967511459}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>36.448196445521205}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>37.129780535443615}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.31628731487427}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>30.12209085444982}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>29.938582222468735}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>33.50557345611348}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>37.48593642184523} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/vi_spec.rb b/spec/technical_analysis/indicators/vi_spec.rb index 5b456cc..67e7248 100644 --- a/spec/technical_analysis/indicators/vi_spec.rb +++ b/spec/technical_analysis/indicators/vi_spec.rb @@ -10,55 +10,55 @@ output = TechnicalAnalysis::Vi.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:negative_vi=>0.9987535631315481, :positive_vi=>0.7711714493088508}}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:negative_vi=>1.0400453579079016, :positive_vi=>0.8594387814137219}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:negative_vi=>0.9136449963918103, :positive_vi=>0.9374983015842824}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:negative_vi=>0.9510765744895432, :positive_vi=>0.9155241699342749}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:negative_vi=>0.9506581829483907, :positive_vi=>0.7977446639361122}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:negative_vi=>1.017756255044391, :positive_vi=>0.73372163931486}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:negative_vi=>1.0107777977366625, :positive_vi=>0.7408837794144069}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:negative_vi=>0.9456323099415208, :positive_vi=>0.8265716374269011}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:negative_vi=>0.9713674816398625, :positive_vi=>0.8198382448638102}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:negative_vi=>1.0059420422342082, :positive_vi=>0.7587530852911607}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:negative_vi=>1.0186513629842182, :positive_vi=>0.7271341463414641}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:negative_vi=>1.053272641569953, :positive_vi=>0.6968210271671884}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:negative_vi=>1.0659261208578774, :positive_vi=>0.6477869675714517}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:negative_vi=>1.0787197159390678, :positive_vi=>0.6861446786495575}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:negative_vi=>1.0499147710692558, :positive_vi=>0.7525644147579889}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:negative_vi=>1.018527704309603, :positive_vi=>0.6562081533662589}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:negative_vi=>1.1182403853648055, :positive_vi=>0.5634420498548615}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:negative_vi=>1.1504168141815485, :positive_vi=>0.5639363354788292}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:negative_vi=>1.2070792620527797, :positive_vi=>0.6046320015251558}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:negative_vi=>1.1658984366885399, :positive_vi=>0.65775873808705}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:negative_vi=>1.1714346511931206, :positive_vi=>0.6287012609627801}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:negative_vi=>1.1564601777941095, :positive_vi=>0.6464192792510783}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:negative_vi=>1.1373201600900555, :positive_vi=>0.6548920237509929}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:negative_vi=>1.1516224812958684, :positive_vi=>0.6987674707967169}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:negative_vi=>1.0746012192731307, :positive_vi=>0.8019709726837323}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:negative_vi=>1.0423007389465182, :positive_vi=>0.7496451535522679}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:negative_vi=>1.0795256042654737, :positive_vi=>0.7516804020221332}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:negative_vi=>1.050514334444714, :positive_vi=>0.7172185077490695}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:negative_vi=>1.136139122315593, :positive_vi=>0.6334605508870221}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:negative_vi=>1.1040510191627, :positive_vi=>0.7505785426583675}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:negative_vi=>1.0422719380259118, :positive_vi=>0.8400547615867511}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:negative_vi=>1.011590726346824, :positive_vi=>0.8266537121415173}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:negative_vi=>0.9867067848168232, :positive_vi=>0.8214508662875287}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:negative_vi=>0.974913770577476, :positive_vi=>0.814344133786256}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:negative_vi=>0.9773071878279123, :positive_vi=>0.8213523084994758}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:negative_vi=>1.067568020631851, :positive_vi=>0.7127001934235981}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:negative_vi=>1.1525346959374216, :positive_vi=>0.6361329800656076}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:negative_vi=>1.1606095395904847, :positive_vi=>0.5994780447390226}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:negative_vi=>1.3088205560235893, :positive_vi=>0.5374882657359492}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:negative_vi=>1.2335085243974138, :positive_vi=>0.636331569664903}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:negative_vi=>1.1655798789007923, :positive_vi=>0.729855612482534}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:negative_vi=>1.1487474529545731, :positive_vi=>0.8037876063766033}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:negative_vi=>1.08671679197995, :positive_vi=>0.8781954887218045}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:negative_vi=>1.1146552806731134, :positive_vi=>0.8035916112018086}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:negative_vi=>1.114675915889877, :positive_vi=>0.7324951224799482}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:negative_vi=>1.0760915145470467, :positive_vi=>0.7417758715458455}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:negative_vi=>1.0577860164333046, :positive_vi=>0.813115261460082}}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:negative_vi=>1.0113586362578701, :positive_vi=>0.8600571901821686}}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:negative_vi=>1.0577860164333046, :positive_vi=>0.813115261460082}}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:negative_vi=>1.0760915145470467, :positive_vi=>0.7417758715458455}}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:negative_vi=>1.114675915889877, :positive_vi=>0.7324951224799482}}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:negative_vi=>1.1146552806731134, :positive_vi=>0.8035916112018086}}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:negative_vi=>1.08671679197995, :positive_vi=>0.8781954887218045}}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:negative_vi=>1.1487474529545731, :positive_vi=>0.8037876063766033}}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:negative_vi=>1.1655798789007923, :positive_vi=>0.729855612482534}}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:negative_vi=>1.2335085243974138, :positive_vi=>0.636331569664903}}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:negative_vi=>1.3088205560235893, :positive_vi=>0.5374882657359492}}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:negative_vi=>1.1606095395904847, :positive_vi=>0.5994780447390226}}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:negative_vi=>1.1525346959374216, :positive_vi=>0.6361329800656076}}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:negative_vi=>1.067568020631851, :positive_vi=>0.7127001934235981}}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:negative_vi=>0.9773071878279123, :positive_vi=>0.8213523084994758}}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:negative_vi=>0.974913770577476, :positive_vi=>0.814344133786256}}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:negative_vi=>0.9867067848168232, :positive_vi=>0.8214508662875287}}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:negative_vi=>1.011590726346824, :positive_vi=>0.8266537121415173}}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:negative_vi=>1.0422719380259118, :positive_vi=>0.8400547615867511}}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:negative_vi=>1.1040510191627, :positive_vi=>0.7505785426583675}}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:negative_vi=>1.136139122315593, :positive_vi=>0.6334605508870221}}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:negative_vi=>1.050514334444714, :positive_vi=>0.7172185077490695}}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:negative_vi=>1.0795256042654737, :positive_vi=>0.7516804020221332}}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:negative_vi=>1.0423007389465182, :positive_vi=>0.7496451535522679}}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:negative_vi=>1.0746012192731307, :positive_vi=>0.8019709726837323}}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:negative_vi=>1.1516224812958684, :positive_vi=>0.6987674707967169}}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:negative_vi=>1.1373201600900555, :positive_vi=>0.6548920237509929}}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:negative_vi=>1.1564601777941095, :positive_vi=>0.6464192792510783}}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:negative_vi=>1.1714346511931206, :positive_vi=>0.6287012609627801}}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:negative_vi=>1.1658984366885399, :positive_vi=>0.65775873808705}}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:negative_vi=>1.2070792620527797, :positive_vi=>0.6046320015251558}}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:negative_vi=>1.1504168141815485, :positive_vi=>0.5639363354788292}}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:negative_vi=>1.1182403853648055, :positive_vi=>0.5634420498548615}}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:negative_vi=>1.018527704309603, :positive_vi=>0.6562081533662589}}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:negative_vi=>1.0499147710692558, :positive_vi=>0.7525644147579889}}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:negative_vi=>1.0787197159390678, :positive_vi=>0.6861446786495575}}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:negative_vi=>1.0659261208578774, :positive_vi=>0.6477869675714517}}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:negative_vi=>1.053272641569953, :positive_vi=>0.6968210271671884}}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:negative_vi=>1.0186513629842182, :positive_vi=>0.7271341463414641}}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:negative_vi=>1.0059420422342082, :positive_vi=>0.7587530852911607}}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:negative_vi=>0.9713674816398625, :positive_vi=>0.8198382448638102}}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:negative_vi=>0.9456323099415208, :positive_vi=>0.8265716374269011}}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:negative_vi=>1.0107777977366625, :positive_vi=>0.7408837794144069}}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:negative_vi=>1.017756255044391, :positive_vi=>0.73372163931486}}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:negative_vi=>0.9506581829483907, :positive_vi=>0.7977446639361122}}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:negative_vi=>0.9510765744895432, :positive_vi=>0.9155241699342749}}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:negative_vi=>0.9136449963918103, :positive_vi=>0.9374983015842824}}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:negative_vi=>1.0400453579079016, :positive_vi=>0.8594387814137219}}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:negative_vi=>0.9987535631315481, :positive_vi=>0.7711714493088508}} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/vpt_spec.rb b/spec/technical_analysis/indicators/vpt_spec.rb index f0a56ba..186726a 100644 --- a/spec/technical_analysis/indicators/vpt_spec.rb +++ b/spec/technical_analysis/indicators/vpt_spec.rb @@ -10,68 +10,68 @@ output = TechnicalAnalysis::Vpt.calculate(input_data) expected_output = [ - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-1903264.3174505206}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-2370279.621573285}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-959554.7990039173}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-1607126.441433344}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-972399.6540759658}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-1070464.7668376141}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-1827517.8777377433}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-1326839.4882367724}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-1151165.4943468445}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-786529.9466468699}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-2158324.481734193}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-1522689.2992524402}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-2274149.490335243}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-3132205.8074873467}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-2949972.4593908517}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-1959004.510023763}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-1146038.8004377298}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-7185217.517024899}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-9060892.67270255}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-8717279.945880784}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-7707600.723227796}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-7883463.234301859}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-8545161.134440955}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-11113790.317206156}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-11580638.32359231}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-13290943.979317216}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-12149014.896876106}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-11748170.533467716}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-13397928.75906581}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-16631473.78435367}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-16666614.749434467}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-17266635.256844807}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-16662634.99217477}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-16752197.088154612}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-14985612.348714761}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-15304600.832189944}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-15517586.252407152}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-14101104.854714246}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-15910856.843135413}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-16386993.991247926}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-17873132.82137613}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-17466268.97188952}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-17729175.804436687}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-17630301.940948576}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-17282902.245502096}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-18582658.71932485}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18985158.397835847}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18546614.21276814}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-20031264.8456338}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-21656330.504158247}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-25370780.481841102}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-26332500.093066465}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22238622.758734256}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22573553.26073845}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-22552168.387219403}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-22218723.601326805}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-22178057.48873647}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31252972.592586517}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-28801593.76496151}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-28923059.940598898}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-27383899.78109331}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-28148662.548589166}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-27383899.78109331} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-28923059.940598898}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-28801593.76496151}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31252972.592586517}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-22178057.48873647}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-22218723.601326805}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-22552168.387219403}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22573553.26073845}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22238622.758734256}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-26332500.093066465}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-25370780.481841102}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-21656330.504158247}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-20031264.8456338}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18546614.21276814}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18985158.397835847}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-18582658.71932485}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-17282902.245502096}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-17630301.940948576}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-17729175.804436687}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-17466268.97188952}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-17873132.82137613}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-16386993.991247926}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-15910856.843135413}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-14101104.854714246}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-15517586.252407152}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-15304600.832189944}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-14985612.348714761}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-16752197.088154612}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-16662634.99217477}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-17266635.256844807}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-16666614.749434467}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-16631473.78435367}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-13397928.75906581}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-11748170.533467716}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-12149014.896876106}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-13290943.979317216}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-11580638.32359231}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-11113790.317206156}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-8545161.134440955}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-7883463.234301859}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-7707600.723227796}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-8717279.945880784}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-9060892.67270255}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-7185217.517024899}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-1146038.8004377298}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-1959004.510023763}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-2949972.4593908517}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-3132205.8074873467}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-2274149.490335243}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-1522689.2992524402}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-2158324.481734193}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-786529.9466468699}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-1151165.4943468445}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-1326839.4882367724}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-1827517.8777377433}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-1070464.7668376141}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-972399.6540759658}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-1607126.441433344}, + {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-959554.7990039173}, + {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-2370279.621573285}, + {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-1903264.3174505206} ] expect(output).to eq(expected_output) diff --git a/spec/technical_analysis/indicators/wr_spec.rb b/spec/technical_analysis/indicators/wr_spec.rb index 49e2d88..86e7727 100644 --- a/spec/technical_analysis/indicators/wr_spec.rb +++ b/spec/technical_analysis/indicators/wr_spec.rb @@ -10,56 +10,56 @@ output = TechnicalAnalysis::Wr.calculate(input_data, period: 14) expected_output = [ - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-73.3779264214046}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-69.64461994076994}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-60.253583241455274}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-29.60308710033065}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-11.080485115766221}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-89.09574468085114}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-86.87643898695312}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-78.51112816577121}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-54.79662317728319}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-60.39907904834988}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-75.82501918649267}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-98.75164257555849}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-97.47686016454276}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-97.61185835849572}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-84.95745264891575}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-79.13807301674446}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-97.67192935509766}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-96.8623265741729}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-96.67016255899316}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-99.50026301946345}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-89.06171600602104}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-90.01505268439534}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-73.20622177621675}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-74.01398601398596}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-71.8823927002365}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-45.9138187221397}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-73.97761994374633}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-81.95026204496244}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-99.28757569508241}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-77.09170624771653}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-75.47431744562708}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-73.29939842665439}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-64.73854696899592}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-90.0509023600186}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-94.55200360198106}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-84.961728950923}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-93.03675048355906}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-94.83805668016194}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-96.88473520249222}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-99.32960706594149}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-62.468960624334926}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-65.7347670250896}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-62.8945342571209}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-57.082371054657386}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-56.38953040800621}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-99.37847562970234}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-76.88330871491881}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-77.4952561669829}, + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-55.55992141453828}, {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-65.72659616137877}, - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-55.55992141453828} + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-77.4952561669829}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-76.88330871491881}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-99.37847562970234}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-56.38953040800621}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-57.082371054657386}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-62.8945342571209}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-65.7347670250896}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-62.468960624334926}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-99.32960706594149}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-96.88473520249222}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-94.83805668016194}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-93.03675048355906}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-84.961728950923}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-94.55200360198106}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-90.0509023600186}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-64.73854696899592}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-73.29939842665439}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-75.47431744562708}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-77.09170624771653}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-99.28757569508241}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-81.95026204496244}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-73.97761994374633}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-45.9138187221397}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-71.8823927002365}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-74.01398601398596}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-73.20622177621675}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-90.01505268439534}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-89.06171600602104}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-99.50026301946345}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-96.67016255899316}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-96.8623265741729}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-97.67192935509766}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-79.13807301674446}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-84.95745264891575}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-97.61185835849572}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-97.47686016454276}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-98.75164257555849}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-75.82501918649267}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-60.39907904834988}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-54.79662317728319}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-78.51112816577121}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-86.87643898695312}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-89.09574468085114}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-11.080485115766221}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-29.60308710033065}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-60.253583241455274}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-69.64461994076994}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-73.3779264214046} ] expect(output).to eq(expected_output) From 921b9c528db764902ffba47c67d99c10f38e51ce Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Feb 2019 12:48:22 -0500 Subject: [PATCH 11/84] Update specs for each indicator - Minor updates to indicators - Test indicator_symbol for each indicator - Test indicator_name for each indicator - Test valid_options for each indicator - Test validate_options for each indicator - Test invalid options for each indicator - Test min_data_size for each indicator --- lib/technical_analysis/helpers/validation.rb | 2 +- lib/technical_analysis/indicators/adi.rb | 4 +-- lib/technical_analysis/indicators/cr.rb | 2 +- lib/technical_analysis/indicators/evm.rb | 8 +++-- lib/technical_analysis/indicators/fi.rb | 3 +- lib/technical_analysis/indicators/macd.rb | 2 +- lib/technical_analysis/indicators/nvi.rb | 2 +- lib/technical_analysis/indicators/obv.rb | 2 +- lib/technical_analysis/indicators/sma.rb | 8 ++--- lib/technical_analysis/indicators/vpt.rb | 2 +- .../technical_analysis/indicators/adi_spec.rb | 34 +++++++++++++++++- .../indicators/adtv_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/adx_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/ao_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/atr_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/bb_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/cci_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/cmf_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/cr_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/dc_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/dlr_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/dpo_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/dr_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/eom_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/evm_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/fi_spec.rb | 36 +++++++++++++++++-- .../indicators/ichimoku_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/kc_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/kst_spec.rb | 36 +++++++++++++++++-- .../indicators/macd_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/mfi_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/mi_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/nvi_spec.rb | 36 +++++++++++++++++-- .../indicators/obv_mean_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/obv_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/rsi_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/sma_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/sr_spec.rb | 36 +++++++++++++++++-- .../indicators/trix_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/tsi_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/uo_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/vi_spec.rb | 36 +++++++++++++++++-- .../technical_analysis/indicators/vpt_spec.rb | 36 +++++++++++++++++-- spec/technical_analysis/indicators/wr_spec.rb | 36 +++++++++++++++++-- 44 files changed, 1173 insertions(+), 84 deletions(-) diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 6d58ec7..f230ad9 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -17,7 +17,7 @@ def self.validate_options(options, valid_options) raise ValidationError.new "No valid options provided." unless valid_options return true if (options.keys - valid_options).empty? - raise ValidationError.new "Invalid options provided. Valid options are #{VALID_OPTIONS.join(", ")}" + raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}" end class ValidationError < StandardError; end diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index 56315c9..189b0e6 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,8 +1,6 @@ module TechnicalAnalysis class Adi < Indicator - VALID_OPTIONS = [].freeze - def self.indicator_symbol "adi" end @@ -17,7 +15,7 @@ def self.valid_options def self.validate_options(options) return true if options == {} - raise ValidationError.new "This indicator doesn't accept any options." + raise Validation::ValidationError.new "This indicator doesn't accept any options." end def self.min_data_size(**params) diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 744fff3..f38ca31 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -17,7 +17,7 @@ def self.validate_options(options) Validation.validate_options(options, valid_options) end - def min_data_size(**params) + def self.min_data_size(**params) 1 end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index 705ca23..032ac57 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -1,7 +1,9 @@ module TechnicalAnalysis - Evm = Eom + class Evm < Eom + + def self.indicator_symbol + "evm" + end - def self.indicator_symbol - "evm" end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index e406d28..2cd161f 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -14,7 +14,8 @@ def self.valid_options end def self.validate_options(options) - true + return true if options == {} + raise Validation::ValidationError.new "This indicator doesn't accept any options." end def self.min_data_size(**params) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index eb1fcba..7a6d9ad 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -10,7 +10,7 @@ def self.indicator_name end def self.valid_options - %i(slow_period signal_period) + %i(fast_period slow_period signal_period price_key) end def self.validate_options(options) diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 0f7cf2b..dfbfadc 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -15,7 +15,7 @@ def self.valid_options def self.validate_options(options) return true if options == {} - raise ValidationError.new "This indicator doesn't accept any options." + raise Validation::ValidationError.new "This indicator doesn't accept any options." end def self.min_data_size(**params) diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 894a03d..7f80fa4 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -15,7 +15,7 @@ def self.valid_options def self.validate_options(options) return true if options == {} - raise ValidationError.new "This indicator doesn't accept any options." + raise Validation::ValidationError.new "This indicator doesn't accept any options." end def self.min_data_size(**params) diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 418e68e..df805c2 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -9,10 +9,6 @@ def self.indicator_name "Simple Moving Average" end - def self.min_data_size(period: 30, **params) - period - end - def self.valid_options %i(period price_key) end @@ -21,6 +17,10 @@ def self.validate_options(options) Validation.validate_options(options, valid_options) end + def self.min_data_size(period: 30, **params) + period + end + # Calculates the simple moving average (SMA) for the data over the given period # https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average # diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index 040ae9e..a15df46 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -15,7 +15,7 @@ def self.valid_options def self.validate_options(options) return true if options == {} - raise ValidationError.new "This indicator doesn't accept any options." + raise Validation::ValidationError.new "This indicator doesn't accept any options." end def self.min_data_size(**params) diff --git a/spec/technical_analysis/indicators/adi_spec.rb b/spec/technical_analysis/indicators/adi_spec.rb index dd4f86b..ab710a2 100644 --- a/spec/technical_analysis/indicators/adi_spec.rb +++ b/spec/technical_analysis/indicators/adi_spec.rb @@ -3,12 +3,13 @@ describe 'Indicators' do describe "ADI" do + indicator = TechnicalAnalysis::Adi describe 'Accumulation/Distribution Index' do it 'Calculates ADI' do input_data = SpecHelper.get_test_data(:volume, :high, :low, :close) - output = TechnicalAnalysis::Adi.calculate(input_data) + output = indicator.calculate(input_data) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-112451134.66006838}, @@ -78,6 +79,37 @@ expect(output).to eq(expected_output) end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('adi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Accumulation/Distribution Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) + end end end end diff --git a/spec/technical_analysis/indicators/adtv_spec.rb b/spec/technical_analysis/indicators/adtv_spec.rb index 6fa3b5e..e34e018 100644 --- a/spec/technical_analysis/indicators/adtv_spec.rb +++ b/spec/technical_analysis/indicators/adtv_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "ADTV" do input_data = SpecHelper.get_test_data(:volume) + indicator = TechnicalAnalysis::Adtv describe 'Average Daily Trading Volume' do it 'Calculates ADTV (22 day)' do - output = TechnicalAnalysis::Adtv.calculate(input_data, period: 22, volume_key: :volume) + output = indicator.calculate(input_data, period: 22, volume_key: :volume) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>49513676.36363637}, @@ -58,7 +59,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Adtv.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('adtv') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Average Daily Trading Volume') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period volume_key)) + end + + it 'Validates options' do + valid_options = { period: 22, volume_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/adx_spec.rb b/spec/technical_analysis/indicators/adx_spec.rb index 06149c5..67047ae 100644 --- a/spec/technical_analysis/indicators/adx_spec.rb +++ b/spec/technical_analysis/indicators/adx_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "ADX" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Adx describe 'Average Directional Index' do it 'Calculates ADX (14 day)' do - output = TechnicalAnalysis::Adx.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}}, @@ -52,7 +53,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Adx.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('adx') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Average Directional Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(8) end end end diff --git a/spec/technical_analysis/indicators/ao_spec.rb b/spec/technical_analysis/indicators/ao_spec.rb index 027cdd2..a7fb9b1 100644 --- a/spec/technical_analysis/indicators/ao_spec.rb +++ b/spec/technical_analysis/indicators/ao_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "AO" do input_data = SpecHelper.get_test_data(:high, :low) + indicator = TechnicalAnalysis::Ao describe 'Awesome Oscillator' do it 'Calculates AO (5 day short period, 34 day long period)' do - output = TechnicalAnalysis::Ao.calculate(input_data, short_period: 5, long_period: 34) + output = indicator.calculate(input_data, short_period: 5, long_period: 34) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-17.518757058823525}, @@ -46,7 +47,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Ao.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('ao') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Awesome Oscillator') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(short_period long_period)) + end + + it 'Validates options' do + valid_options = { short_period: 5, long_period: 34 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { long_period: 20 } + expect(indicator.min_data_size(options)).to eq(20) end end end diff --git a/spec/technical_analysis/indicators/atr_spec.rb b/spec/technical_analysis/indicators/atr_spec.rb index ea42966..34fab31 100644 --- a/spec/technical_analysis/indicators/atr_spec.rb +++ b/spec/technical_analysis/indicators/atr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "ATR" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Atr describe 'Average True Range' do it 'Calculates ATR (14 day)' do - output = TechnicalAnalysis::Atr.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>6.103013600253306}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Atr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('atr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Average True Range') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/bb_spec.rb b/spec/technical_analysis/indicators/bb_spec.rb index 6c7bb19..4847522 100644 --- a/spec/technical_analysis/indicators/bb_spec.rb +++ b/spec/technical_analysis/indicators/bb_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "BB" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Bb describe 'Bollinger Bands' do it 'Calculates BB (20, 2)' do - output = TechnicalAnalysis::Bb.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close) + output = indicator.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}}, @@ -60,7 +61,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Bb.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('bb') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Bollinger Bands') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period standard_deviations price_key)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/cci_spec.rb b/spec/technical_analysis/indicators/cci_spec.rb index eebdd6c..196574d 100644 --- a/spec/technical_analysis/indicators/cci_spec.rb +++ b/spec/technical_analysis/indicators/cci_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "CCI" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Cci describe 'Commodity Channel Index' do it 'Calculates CCI (20 day)' do - output = TechnicalAnalysis::Cci.calculate(input_data, period: 20, constant: 0.015) + output = indicator.calculate(input_data, period: 20, constant: 0.015) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-48.14847062019609}, @@ -60,7 +61,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Cci.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('cci') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Commodity Channel Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period constant)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/cmf_spec.rb b/spec/technical_analysis/indicators/cmf_spec.rb index 480530e..302e455 100644 --- a/spec/technical_analysis/indicators/cmf_spec.rb +++ b/spec/technical_analysis/indicators/cmf_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "CMF" do input_data = SpecHelper.get_test_data(:high, :low, :close, :volume) + indicator = TechnicalAnalysis::Cmf describe 'Chaikin Money Flow' do it 'Calculates CMF (20 day)' do - output = TechnicalAnalysis::Cmf.calculate(input_data, period: 20) + output = indicator.calculate(input_data, period: 20) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.14148236474171028}, @@ -60,7 +61,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Cmf.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('cmf') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Chaikin Money Flow') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/cr_spec.rb b/spec/technical_analysis/indicators/cr_spec.rb index d59ea6c..db8fc46 100644 --- a/spec/technical_analysis/indicators/cr_spec.rb +++ b/spec/technical_analysis/indicators/cr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "CR" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Cr describe 'Cumulative Return' do it 'Calculates CR' do - output = TechnicalAnalysis::Cr.calculate(input_data, price_key: :close) + output = indicator.calculate(input_data, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.3242385507118614}, @@ -79,7 +80,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Cr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('cr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Cumulative Return') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(price_key)) + end + + it 'Validates options' do + valid_options = { price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) end end end diff --git a/spec/technical_analysis/indicators/dc_spec.rb b/spec/technical_analysis/indicators/dc_spec.rb index 3734d4b..8ad3865 100644 --- a/spec/technical_analysis/indicators/dc_spec.rb +++ b/spec/technical_analysis/indicators/dc_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "DC" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Dc describe 'Donchian Channel' do it 'Calculates DC (20 day)' do - output = TechnicalAnalysis::Dc.calculate(input_data, period: 20, price_key: :close) + output = indicator.calculate(input_data, period: 20, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, @@ -60,7 +61,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Dc.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('dc') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Donchian Channel') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/dlr_spec.rb b/spec/technical_analysis/indicators/dlr_spec.rb index 4dcebf6..0a9a384 100644 --- a/spec/technical_analysis/indicators/dlr_spec.rb +++ b/spec/technical_analysis/indicators/dlr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "DLR" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Dlr describe 'Daily Log Return' do it 'Calculates Daily Log Return' do - output = TechnicalAnalysis::Dlr.calculate(input_data, price_key: :close) + output = indicator.calculate(input_data, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01683917971506794}, @@ -79,7 +80,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Dlr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('dlr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Daily Log Return') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(price_key)) + end + + it 'Validates options' do + valid_options = { price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) end end end diff --git a/spec/technical_analysis/indicators/dpo_spec.rb b/spec/technical_analysis/indicators/dpo_spec.rb index 89d5241..c0d262a 100644 --- a/spec/technical_analysis/indicators/dpo_spec.rb +++ b/spec/technical_analysis/indicators/dpo_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "DPO" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Dpo describe 'Detrended Price Oscillator' do it 'Calculates DPO (20 day)' do - output = TechnicalAnalysis::Dpo.calculate(input_data, period: 20, price_key: :close) + output = indicator.calculate(input_data, period: 20, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-15.774999999999977}, @@ -50,7 +51,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Dpo.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('dpo') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Detrended Price Oscillator') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(6) end end end diff --git a/spec/technical_analysis/indicators/dr_spec.rb b/spec/technical_analysis/indicators/dr_spec.rb index 3deeab7..2232919 100644 --- a/spec/technical_analysis/indicators/dr_spec.rb +++ b/spec/technical_analysis/indicators/dr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "DR" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Dr describe 'Daily Return' do it 'Calculates Daily Return' do - output = TechnicalAnalysis::Dr.calculate(input_data, price_key: :close) + output = indicator.calculate(input_data, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01698175787728018}, @@ -79,7 +80,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Dr.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('dr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Daily Return') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(price_key)) + end + + it 'Validates options' do + valid_options = { price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) end end end diff --git a/spec/technical_analysis/indicators/eom_spec.rb b/spec/technical_analysis/indicators/eom_spec.rb index 920fe66..5db67b6 100644 --- a/spec/technical_analysis/indicators/eom_spec.rb +++ b/spec/technical_analysis/indicators/eom_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "EoM" do input_data = SpecHelper.get_test_data(:high, :low, :volume) + indicator = TechnicalAnalysis::Eom describe 'Ease of Movement' do it 'Calculates EoM (14 day)' do - output = TechnicalAnalysis::Eom.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Eom.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('eom') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Ease of Movement') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb index 071d04a..8e05224 100644 --- a/spec/technical_analysis/indicators/evm_spec.rb +++ b/spec/technical_analysis/indicators/evm_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "EVM" do input_data = SpecHelper.get_test_data(:high, :low, :volume) + indicator = TechnicalAnalysis::Evm describe 'Ease of Movement' do it 'Calculates EVM (14 day)' do - output = TechnicalAnalysis::Evm.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Evm.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('evm') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Ease of Movement') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/fi_spec.rb b/spec/technical_analysis/indicators/fi_spec.rb index 8358b5b..0b8a40a 100644 --- a/spec/technical_analysis/indicators/fi_spec.rb +++ b/spec/technical_analysis/indicators/fi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "FI" do input_data = SpecHelper.get_test_data(:close, :volume) + indicator = TechnicalAnalysis::Fi describe 'Forced Index' do it 'Calculates FI' do - output = TechnicalAnalysis::Fi.calculate(input_data) + output = indicator.calculate(input_data) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>115287987.2000001}, @@ -78,7 +79,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Fi.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('fi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Force Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(2) end end end diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb index 3a06890..36d5637 100644 --- a/spec/technical_analysis/indicators/ichimoku_spec.rb +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "Ichimoku" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Ichimoku describe 'Ichimoku' do it 'Calculates Ichimoku' do - output = TechnicalAnalysis::Ichimoku.calculate(input_data, low_period: 3, medium_period: 10, high_period: 20) + output = indicator.calculate(input_data, low_period: 3, medium_period: 10, high_period: 20) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}}, @@ -55,7 +56,38 @@ high_period = 40 size_limit = (medium_period + high_period + 1) - expect {TechnicalAnalysis::Ichimoku.calculate(input_data, high_period: size_limit)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, high_period: size_limit)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('ichimoku') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Ichimoku Kinko Hyo') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(low_period medium_period high_period)) + end + + it 'Validates options' do + valid_options = { low_period: 9, medium_period: 26, high_period: 52 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { medium_period: 4, high_period: 10 } + expect(indicator.min_data_size(options)).to eq(12) end end end diff --git a/spec/technical_analysis/indicators/kc_spec.rb b/spec/technical_analysis/indicators/kc_spec.rb index cd91bc7..6105590 100644 --- a/spec/technical_analysis/indicators/kc_spec.rb +++ b/spec/technical_analysis/indicators/kc_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "KC" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Kc describe 'Keltner Channel' do it 'Calculates KC (10 day)' do - output = TechnicalAnalysis::Kc.calculate(input_data, period: 10) + output = indicator.calculate(input_data, period: 10) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}}, @@ -70,7 +71,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Kc.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('kc') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Keltner Channel') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/kst_spec.rb b/spec/technical_analysis/indicators/kst_spec.rb index 9a98037..97a3478 100644 --- a/spec/technical_analysis/indicators/kst_spec.rb +++ b/spec/technical_analysis/indicators/kst_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "KST" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Kst describe 'Know Sure Thing' do it 'Calculates KST' do - output = TechnicalAnalysis::Kst.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close) + output = indicator.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-140.9140022298261}, @@ -38,7 +39,38 @@ it "Throws exception if not enough data" do roc4 = 60 sma4 = 30 - expect {TechnicalAnalysis::Kst.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('kst') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Know Sure Thing') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period roc1 roc2 roc3 roc4 sma1 sma2 sma3 sma4 price_key)) + end + + it 'Validates options' do + valid_options = { roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { roc4: 30, sma4: 15 } + expect(indicator.min_data_size(options)).to eq(44) end end end diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb index 529a55e..2ce42d0 100644 --- a/spec/technical_analysis/indicators/macd_spec.rb +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "MACD" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Macd describe 'Moving Average Convergence Divergence' do it 'Calculates MACD (12, 26, 9)' do - output = TechnicalAnalysis::Macd.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close) + output = indicator.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}}, @@ -46,7 +47,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Macd.calculate(input_data, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('macd') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Moving Average Convergence Divergence') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(fast_period slow_period signal_period price_key)) + end + + it 'Validates options' do + valid_options = { fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { fast_period: 12, slow_period: 24, signal_period: 10, price_key: :close } + expect(indicator.min_data_size(options)).to eq(34) end end end diff --git a/spec/technical_analysis/indicators/mfi_spec.rb b/spec/technical_analysis/indicators/mfi_spec.rb index 8aebc5f..7fcc9df 100644 --- a/spec/technical_analysis/indicators/mfi_spec.rb +++ b/spec/technical_analysis/indicators/mfi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "MFI" do input_data = SpecHelper.get_test_data(:high, :low, :close, :volume) + indicator = TechnicalAnalysis::Mfi describe 'Money Flow Index' do it 'Calculates MFI (14 day)' do - output = TechnicalAnalysis::Mfi.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>50.72343663578981}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Mfi.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('mfi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Money Flow Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/mi_spec.rb b/spec/technical_analysis/indicators/mi_spec.rb index 9f908f6..fb133f9 100644 --- a/spec/technical_analysis/indicators/mi_spec.rb +++ b/spec/technical_analysis/indicators/mi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "MI" do input_data = SpecHelper.get_test_data(:high, :low) + indicator = TechnicalAnalysis::Mi describe 'Simple Mass Index' do it 'Calculates MI' do - output = TechnicalAnalysis::Mi.calculate(input_data, ema_period: 9, sum_period: 25) + output = indicator.calculate(input_data, ema_period: 9, sum_period: 25) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>24.77520633216394}, @@ -39,7 +40,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Mi.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('mi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Mass Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(ema_period sum_period)) + end + + it 'Validates options' do + valid_options = { ema_period: 9, sum_period: 25 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { ema_period: 10, sum_period: 20 } + expect(indicator.min_data_size(options)).to eq(38) end end end diff --git a/spec/technical_analysis/indicators/nvi_spec.rb b/spec/technical_analysis/indicators/nvi_spec.rb index e792cd9..64f7fe4 100644 --- a/spec/technical_analysis/indicators/nvi_spec.rb +++ b/spec/technical_analysis/indicators/nvi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "NVI" do input_data = SpecHelper.get_test_data(:close, :volume) + indicator = TechnicalAnalysis::Nvi describe 'Negative Volume Index' do it 'Calculates NVI' do - output = TechnicalAnalysis::Nvi.calculate(input_data) + output = indicator.calculate(input_data) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>1002.8410612825647}, @@ -79,7 +80,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Nvi.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('nvi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Negative Volume Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) end end end diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb index 3b2ffe5..05ae85d 100644 --- a/spec/technical_analysis/indicators/obv_mean_spec.rb +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "OBV Mean" do input_data = SpecHelper.get_test_data(:close, :volume) + indicator = TechnicalAnalysis::ObvMean describe 'On-balance Volume Mean' do it 'Calculates OBV Mean (10 day)' do - output = TechnicalAnalysis::ObvMean.calculate(input_data, period: 10) + output = indicator.calculate(input_data, period: 10) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-642606913.0}, @@ -69,7 +70,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::ObvMean.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('obv_mean') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('On-balance Volume Mean') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/obv_spec.rb b/spec/technical_analysis/indicators/obv_spec.rb index 98ad833..1c6c9b6 100644 --- a/spec/technical_analysis/indicators/obv_spec.rb +++ b/spec/technical_analysis/indicators/obv_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "OBV" do input_data = SpecHelper.get_test_data(:close, :volume) + indicator = TechnicalAnalysis::Obv describe 'On-balance Volume' do it 'Calculates OBV' do - output = TechnicalAnalysis::Obv.calculate(input_data) + output = indicator.calculate(input_data) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-591085010}, @@ -79,7 +80,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Obv.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('obv') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('On-balance Volume') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) end end end diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb index c4443fc..5f6aec7 100644 --- a/spec/technical_analysis/indicators/rsi_spec.rb +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "RSI" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Rsi describe 'Relative Strength Index' do it 'Calculates RSI (14 day)' do - output = TechnicalAnalysis::Rsi.calculate(input_data, period: 14, price_key: :close) + output = indicator.calculate(input_data, period: 14, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>41.01572095202713}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Rsi.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('rsi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Relative Strength Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index 8bb4c68..7e2dfd2 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "SMA" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Sma describe 'Simple Moving Average' do it 'Calculates SMA (5 day)' do - output = TechnicalAnalysis::Sma.calculate(input_data, period: 5, price_key: :close) + output = indicator.calculate(input_data, period: 5, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488}, @@ -75,7 +76,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Sma.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('sma') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Simple Moving Average') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end diff --git a/spec/technical_analysis/indicators/sr_spec.rb b/spec/technical_analysis/indicators/sr_spec.rb index bec09d8..4d16e71 100644 --- a/spec/technical_analysis/indicators/sr_spec.rb +++ b/spec/technical_analysis/indicators/sr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "SR" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Sr describe 'Stochastic Oscillator' do it 'Calculates SR (14 day)' do - output = TechnicalAnalysis::Sr.calculate(input_data, period: 14, signal_period: 3) + output = indicator.calculate(input_data, period: 14, signal_period: 3) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:sr=>44.44007858546172, :sr_signal=>33.739408752366685}}, @@ -64,7 +65,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Sr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('sr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Stochastic Oscillator') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period signal_period)) + end + + it 'Validates options' do + valid_options = { period: 22, signal_period: 4 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4, signal_period: 2 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/trix_spec.rb b/spec/technical_analysis/indicators/trix_spec.rb index ae7a83a..bb0203b 100644 --- a/spec/technical_analysis/indicators/trix_spec.rb +++ b/spec/technical_analysis/indicators/trix_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "TRIX" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Trix describe 'Triple Exponential Average' do it 'Calculates TRIX (15 day)' do - output = TechnicalAnalysis::Trix.calculate(input_data, period: 15, price_key: :close) + output = indicator.calculate(input_data, period: 15, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.007522826289174942}, @@ -36,7 +37,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Trix.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('trix') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Triple Exponential Average') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(11) end end end diff --git a/spec/technical_analysis/indicators/tsi_spec.rb b/spec/technical_analysis/indicators/tsi_spec.rb index 949b4f7..29346a7 100644 --- a/spec/technical_analysis/indicators/tsi_spec.rb +++ b/spec/technical_analysis/indicators/tsi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "TSI" do input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Tsi describe 'True Strength Index' do it 'Calculates True Strength Index' do - output = TechnicalAnalysis::Tsi.calculate(input_data, low_period: 13, high_period: 25, price_key: :close) + output = indicator.calculate(input_data, low_period: 13, high_period: 25, price_key: :close) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-28.91017661103889}, @@ -47,7 +48,38 @@ size_limit = low_period + high_period - 1 input_data = input_data.first(size_limit) - expect {TechnicalAnalysis::Tsi.calculate(input_data, low_period: low_period, high_period: high_period, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, low_period: low_period, high_period: high_period, price_key: :close)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('tsi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('True Strength Index') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(low_period high_period price_key)) + end + + it 'Validates options' do + valid_options = { low_period: 10, high_period: 20, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { low_period: 10, high_period: 20 } + expect(indicator.min_data_size(options)).to eq(30) end end end diff --git a/spec/technical_analysis/indicators/uo_spec.rb b/spec/technical_analysis/indicators/uo_spec.rb index f910452..aee154c 100644 --- a/spec/technical_analysis/indicators/uo_spec.rb +++ b/spec/technical_analysis/indicators/uo_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "UO" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Uo describe 'Ultimate Oscillator' do it 'Calculates UO (5 day)' do - output = TechnicalAnalysis::Uo.calculate(input_data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) + output = indicator.calculate(input_data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>47.28872762629681}, @@ -51,7 +52,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Uo.calculate(input_data, long_period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, long_period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('uo') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Ultimate Oscillator') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(short_period medium_period long_period short_weight medium_weight long_weight)) + end + + it 'Validates options' do + valid_options = { short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { short_period: 7, medium_period: 14, long_period: 20, short_weight: 4, medium_weight: 2, long_weight: 1 } + expect(indicator.min_data_size(options)).to eq(21) end end end diff --git a/spec/technical_analysis/indicators/vi_spec.rb b/spec/technical_analysis/indicators/vi_spec.rb index 67e7248..e0d6225 100644 --- a/spec/technical_analysis/indicators/vi_spec.rb +++ b/spec/technical_analysis/indicators/vi_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "VI" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Vi describe 'Vortex Indicator' do it 'Calculates VI (14 day)' do - output = TechnicalAnalysis::Vi.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}}, @@ -65,7 +66,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Vi.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('vi') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Vortex Indicator') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(5) end end end diff --git a/spec/technical_analysis/indicators/vpt_spec.rb b/spec/technical_analysis/indicators/vpt_spec.rb index 186726a..e12bd3f 100644 --- a/spec/technical_analysis/indicators/vpt_spec.rb +++ b/spec/technical_analysis/indicators/vpt_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "VPT" do input_data = SpecHelper.get_test_data(:close, :volume) + indicator = TechnicalAnalysis::Vpt describe 'Volume-Price Trend' do it 'Calculates VPT' do - output = TechnicalAnalysis::Vpt.calculate(input_data) + output = indicator.calculate(input_data) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-27383899.78109331}, @@ -78,7 +79,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Vpt.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('vpt') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Volume-price Trend') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(2) end end end diff --git a/spec/technical_analysis/indicators/wr_spec.rb b/spec/technical_analysis/indicators/wr_spec.rb index 86e7727..0bdced6 100644 --- a/spec/technical_analysis/indicators/wr_spec.rb +++ b/spec/technical_analysis/indicators/wr_spec.rb @@ -4,10 +4,11 @@ describe 'Indicators' do describe "WR" do input_data = SpecHelper.get_test_data(:high, :low, :close) + indicator = TechnicalAnalysis::Wr describe 'Williams %R' do it 'Calculates Williams %R' do - output = TechnicalAnalysis::Wr.calculate(input_data, period: 14) + output = indicator.calculate(input_data, period: 14) expected_output = [ {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-55.55992141453828}, @@ -66,7 +67,38 @@ end it "Throws exception if not enough data" do - expect {TechnicalAnalysis::Wr.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('wr') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Williams %R') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period)) + end + + it 'Validates options' do + valid_options = { period: 22 } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) end end end From 6ca431df5e8f0121cba2dc219d1e6aba86a08ca7 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Feb 2019 14:37:46 -0500 Subject: [PATCH 12/84] Create specs for Indicator --- .../indicators/indicator_spec.rb | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 spec/technical_analysis/indicators/indicator_spec.rb diff --git a/spec/technical_analysis/indicators/indicator_spec.rb b/spec/technical_analysis/indicators/indicator_spec.rb new file mode 100644 index 0000000..c8a07bc --- /dev/null +++ b/spec/technical_analysis/indicators/indicator_spec.rb @@ -0,0 +1,119 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "Indicator" do + indicator = TechnicalAnalysis::Indicator + + it 'Returns nil on a nonexistant indicator' do + nonexistant_indicator = indicator.find('test') + expect(nonexistant_indicator).to eq(nil) + end + + it 'Finds an indicator' do + sma = indicator.find('sma') + expect(sma).to eq(TechnicalAnalysis::Sma) + end + + describe 'Calculations' do + it 'Returns nil on a nonexistant calculation' do + calculation = indicator.calculate('sma', [], :test, { period: 20, price_key: :close }) + expect(calculation).to eq(nil) + end + + it 'Calculates indicator_name' do + indicator_name = indicator.calculate('sma', [], :indicator_name, { period: 20, price_key: :close }) + expect(indicator_name).to eq('Simple Moving Average') + end + + it 'Calculates indicator_symbol' do + indicator_name = indicator.calculate('sma', [], :indicator_symbol, { period: 20, price_key: :close }) + expect(indicator_name).to eq('sma') + end + + it 'Calculates min_data_size' do + min_data_size = indicator.calculate('sma', [], :min_data_size, { period: 20, price_key: :close }) + expect(min_data_size).to eq(20) + end + + it 'Calculates valid_options' do + valid_options = indicator.calculate('sma', [], :valid_options, { period: 20, price_key: :close }) + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Calculates validate_options' do + options_validated = indicator.calculate('sma', [], :validate_options, { period: 20, price_key: :close }) + expect(options_validated).to eq(true) + end + + it 'Calculates technicals' do + input_data = SpecHelper.get_test_data(:close) + output = indicator.calculate('sma', input_data, :technicals, { period: 5, price_key: :close }) + + expected_output = [ + {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488}, + {:date_time=>"2019-01-08T00:00:00.000Z", :value=>149.41}, + {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, + {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, + {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, + {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, + {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, + {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, + {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, + {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, + {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, + {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, + {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, + {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, + {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, + {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, + {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, + {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, + {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, + {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, + {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, + {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, + {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, + {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, + {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, + {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, + {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, + {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, + {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, + {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, + {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, + {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, + {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, + {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, + {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, + {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, + {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, + {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, + {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, + {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, + {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, + {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, + {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, + {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, + {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, + {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, + {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, + {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, + {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, + {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, + {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, + {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, + {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, + {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, + {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, + {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, + {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43} + ] + + expect(output).to eq(expected_output) + end + end + end +end From f58855eb734c5cb86b99be2237991307a97eff5e Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Feb 2019 16:35:26 -0500 Subject: [PATCH 13/84] Change params to integers inside calculations --- lib/technical_analysis/indicators/adtv.rb | 3 ++- lib/technical_analysis/indicators/adx.rb | 3 ++- lib/technical_analysis/indicators/ao.rb | 4 +++- lib/technical_analysis/indicators/atr.rb | 3 ++- lib/technical_analysis/indicators/bb.rb | 4 +++- lib/technical_analysis/indicators/cci.rb | 4 +++- lib/technical_analysis/indicators/cmf.rb | 3 ++- lib/technical_analysis/indicators/dc.rb | 3 ++- lib/technical_analysis/indicators/dpo.rb | 3 ++- lib/technical_analysis/indicators/eom.rb | 3 ++- lib/technical_analysis/indicators/ichimoku.rb | 5 ++++- lib/technical_analysis/indicators/kc.rb | 3 ++- lib/technical_analysis/indicators/kst.rb | 10 +++++++++- lib/technical_analysis/indicators/macd.rb | 5 ++++- lib/technical_analysis/indicators/mfi.rb | 3 ++- lib/technical_analysis/indicators/mi.rb | 4 +++- lib/technical_analysis/indicators/obv_mean.rb | 3 ++- lib/technical_analysis/indicators/rsi.rb | 3 ++- lib/technical_analysis/indicators/sma.rb | 3 ++- lib/technical_analysis/indicators/sr.rb | 4 +++- lib/technical_analysis/indicators/trix.rb | 3 ++- lib/technical_analysis/indicators/tsi.rb | 4 +++- lib/technical_analysis/indicators/uo.rb | 8 +++++++- lib/technical_analysis/indicators/vi.rb | 3 ++- lib/technical_analysis/indicators/wr.rb | 3 ++- 25 files changed, 72 insertions(+), 25 deletions(-) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index af516d7..497e7b9 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 22, **params) - period + period.to_i end # Calculates the average daily trading volume (ADTV) for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 22, **params) # @param volume_key [Symbol] The hash key for the volume data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 22, volume_key: :value) + period = period.to_i Validation.validate_numeric_data(data, volume_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 82a4ef1..4be4aee 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period * 2 + period.to_i * 2 end # Calculates the average directional index (ADX) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given period to calculate the ADX # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period * 2) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index db24bb0..82ece58 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(long_period: 34, **params) - long_period + long_period.to_i end # Calculates the awesome oscillator for the data over the given period @@ -29,6 +29,8 @@ def self.min_data_size(long_period: 34, **params) # @param long_period [Integer] The given period to calculate the long period SMA # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, short_period: 5, long_period: 34) + short_period = short_period.to_i + long_period = long_period.to_i Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, long_period) diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 87e90d0..0a0ce24 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period + 1 + period.to_i + 1 end # Calculates the average true range (ATR) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given period to calculate the ATR # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 784d779..c740243 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 20, **params) - period + period.to_i end # Calculates the bollinger bands (BB) for the data over the given period @@ -30,6 +30,8 @@ def self.min_data_size(period: 20, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) + period = period.to_i + standard_deviations = standard_deviations.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 692b029..22ad548 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 20, **params) - period + period.to_i end # Calculates the commodity channel index (CCI) for the data over the given period @@ -29,6 +29,8 @@ def self.min_data_size(period: 20, **params) # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of CCI values would fall between −100 and +100 # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20, constant: 0.015) + period = period.to_i + constant = constant.to_f Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index f4055fd..15d6715 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 20) - period + period.to_i end # Calculates the chaikin money flow (CMF) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 20) # @param period [Integer] The given period to calculate the CMF # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index e6fcef6..962edd7 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 20, **params) - period + period.to_i end # Calculates the donchian channel (DC) for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 20, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20, price_key: :value) + period = period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 53b75ed..ee91f79 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 20, **params) - period + (period / 2) + period.to_i + (period.to_i / 2) end # Calculates the detrended price oscillator for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 20, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20, price_key: :value) + period = period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period + (period / 2)) diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 2118a6b..e2c9cd7 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period + 1 + period.to_i + 1 end # Calculates the ease of movement (EoM and EVM) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given period to calculate the Eom / EVM # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 75832e9..ac21277 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(medium_period: 26, high_period: 52, **params) - high_period + medium_period - 2 + high_period.to_i + medium_period.to_i - 2 end # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimoku) for the data over the given period @@ -35,6 +35,9 @@ def self.min_data_size(medium_period: 26, high_period: 52, **params) # @param high_period [Integer] The given period to calculate senkou_span_b (Leadning Span B) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) + low_period = low_period.to_i + medium_period = medium_period.to_i + high_period = high_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, high_period + medium_period - 2) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 8482f60..91888b4 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 10) - period + period.to_i end # Calculates the keltner channel (KC) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 10) # @param period [Integer] The given period to calculate the KC # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 10) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index b9d5a0b..e1ac1b3 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(roc4: 30, sma4: 15, **params) - roc4 + sma4 - 1 + roc4.to_i + sma4.to_i - 1 end # Calculates the know sure thing (KST) for the data over the given period @@ -36,6 +36,14 @@ def self.min_data_size(roc4: 30, sma4: 15, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value) + roc1 = roc1.to_i + roc2 = roc2.to_i + roc3 = roc3.to_i + roc4 = roc4.to_i + sma1 = sma1.to_i + sma2 = sma2.to_i + sma3 = sma3.to_i + sma4 = sma4.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, roc4 + sma4 - 1) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 7a6d9ad..5f2905a 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(slow_period: 26, signal_period: 9, **params) - slow_period + signal_period + slow_period.to_i + signal_period.to_i end # Calculates the moving average convergence divergence (MACD) for the data over the given period @@ -31,6 +31,9 @@ def self.min_data_size(slow_period: 26, signal_period: 9, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :value) + fast_period = fast_period.to_i + slow_period = slow_period.to_i + signal_period = signal_period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, slow_period + signal_period) diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 90a87d9..df7cce4 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period + 1 + period.to_i + 1 end # Calculates the money flow index (MFI) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given period to calculate the MFI # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 85a4b4b..5a37169 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(ema_period: 9, sum_period: 25) - (ema_period * 2) + sum_period - 2 + (ema_period.to_i * 2) + sum_period.to_i - 2 end # Calculates the mass index (MI) for the data over the given period @@ -29,6 +29,8 @@ def self.min_data_size(ema_period: 9, sum_period: 25) # @param period [Integer] The given period to calculate the MI # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, ema_period: 9, sum_period: 25) + ema_period = ema_period.to_i + sum_period = sum_period.to_i Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, (ema_period * 2) + sum_period - 2) diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 94ff3a5..4342fc3 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 10) - period + period.to_i end # Calculates the on-balance volume mean (OBV mean) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 10) # @param period [Integer] The given period to calculate the OBV mean # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 10) + period = period.to_i Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 3dcb8ae..39e2ad4 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14, **params) - period + 1 + period.to_i + 1 end # Calculates the relative strength index for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 14, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14, price_key: :value) + period = period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index df805c2..ef183b0 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 30, **params) - period + period.to_i end # Calculates the simple moving average (SMA) for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 30, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 30, price_key: :value) + period = period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 45c4764..8bd356d 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14, signal_period: 3) - period + signal_period - 1 + period.to_i + signal_period.to_i - 1 end # Calculates the stochastic oscillator (%K) for the data over the given period @@ -28,6 +28,8 @@ def self.min_data_size(period: 14, signal_period: 3) # @param period [Integer] The given period to calculate the SR # @return [Array] Array of hashes with keys(:date_time, :value) def self.calculate(data, period: 14, signal_period: 3) + period = period.to_i + signal_period = signal_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period + signal_period - 1) diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 4d93766..b5dbba1 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 15, **params) - (period * 3) - 1 + (period.to_i * 3) - 1 end # Calculates the triple exponential average (Trix) for the data over the given period @@ -29,6 +29,7 @@ def self.min_data_size(period: 15, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 15, price_key: :value) + period = period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, ((period * 3) - 1)) diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index a030aa1..ba1d65b 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(low_period: 13, high_period: 25, **params) - low_period + high_period + low_period.to_i + high_period.to_i end # Calculates the true strength index (TSI) for the data over the given period @@ -30,6 +30,8 @@ def self.min_data_size(low_period: 13, high_period: 25, **params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) + low_period = low_period.to_i + high_period = high_period.to_i Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, low_period + high_period) diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index d9e1cf7..b854866 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(long_period: 28, **params) - long_period + 1 + long_period.to_i + 1 end # Calculates the ultimate oscillator (UO) for the data over the given period @@ -33,6 +33,12 @@ def self.min_data_size(long_period: 28, **params) # @param long_weight [Float] Weight of long Buying Pressure average for UO # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) + short_period = short_period.to_i + medium_period = medium_period.to_i + long_period = long_period.to_i + short_weight = short_weight.to_f + medium_weight = medium_weight.to_f + long_weight = long_weight.to_f Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, long_period + 1) diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 7d05b32..3c6550f 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period + 1 + period.to_i + 1 end # Calculates the vortex indicator (VI) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given period to calculate the VI # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 40d3594..44fcf88 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(period: 14) - period + period.to_i end # Calculates the Williams %R (WR) for the data over the given period @@ -28,6 +28,7 @@ def self.min_data_size(period: 14) # @param period [Integer] The given look-back period to calculate the WR # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14) + period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, period) From 6dfcaf0e76b7f0c9ab61595aa79d6c16f936c8f2 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Feb 2019 18:25:48 -0500 Subject: [PATCH 14/84] Symbolize price_key in calculations --- lib/technical_analysis/indicators/adtv.rb | 1 + lib/technical_analysis/indicators/bb.rb | 1 + lib/technical_analysis/indicators/cr.rb | 1 + lib/technical_analysis/indicators/dc.rb | 1 + lib/technical_analysis/indicators/dlr.rb | 1 + lib/technical_analysis/indicators/dpo.rb | 1 + lib/technical_analysis/indicators/dr.rb | 1 + lib/technical_analysis/indicators/kst.rb | 1 + lib/technical_analysis/indicators/macd.rb | 1 + lib/technical_analysis/indicators/rsi.rb | 1 + lib/technical_analysis/indicators/sma.rb | 1 + lib/technical_analysis/indicators/trix.rb | 1 + lib/technical_analysis/indicators/tsi.rb | 1 + 13 files changed, 13 insertions(+) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 497e7b9..624eea8 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 22, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 22, volume_key: :value) period = period.to_i + volume_key = volume_key.to_sym Validation.validate_numeric_data(data, volume_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index c740243..16e9bd7 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -32,6 +32,7 @@ def self.min_data_size(period: 20, **params) def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) period = period.to_i standard_deviations = standard_deviations.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index f38ca31..ca80133 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -28,6 +28,7 @@ def self.min_data_size(**params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, price_key: :value) + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, 1) diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 962edd7..72addd3 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 20, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) 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, period) diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 1d69aeb..c695730 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -29,6 +29,7 @@ def self.min_data_size(**params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, price_key: :value) + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, 1) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index ee91f79..dd4526e 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 20, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) 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, period + (period / 2)) diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 4d08941..f01b890 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -28,6 +28,7 @@ def self.min_data_size(**params) # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, price_key: :value) + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, 1) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index e1ac1b3..eea6ae7 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -44,6 +44,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: sma2 = sma2.to_i sma3 = sma3.to_i sma4 = sma4.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, roc4 + sma4 - 1) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 5f2905a..cf1ce2a 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -34,6 +34,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri fast_period = fast_period.to_i slow_period = slow_period.to_i signal_period = signal_period.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, slow_period + signal_period) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 39e2ad4..6f75542 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 14, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14, price_key: :value) period = period.to_i + price_keky = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period + 1) diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index ef183b0..7202849 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 30, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 30, price_key: :value) period = period.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index b5dbba1..7f95a2c 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -30,6 +30,7 @@ def self.min_data_size(period: 15, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 15, price_key: :value) period = period.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, ((period * 3) - 1)) diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index ba1d65b..1df5a2d 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -32,6 +32,7 @@ def self.min_data_size(low_period: 13, high_period: 25, **params) def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) low_period = low_period.to_i high_period = high_period.to_i + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, low_period + high_period) From 19010e93801fd28b67659823826c076214c03dde Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 4 Feb 2019 18:30:02 -0500 Subject: [PATCH 15/84] Fix typo --- lib/technical_analysis/indicators/rsi.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 6f75542..784af68 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -30,7 +30,7 @@ def self.min_data_size(period: 14, **params) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 14, price_key: :value) period = period.to_i - price_keky = price_key.to_sym + price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period + 1) From 4f93751b4a5e7ca1823bb8f363c2d8eeda347c42 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Feb 2019 14:32:21 -0500 Subject: [PATCH 16/84] Minor typo updates --- lib/technical_analysis/indicators/bb.rb | 4 ++-- lib/technical_analysis/indicators/ichimoku.rb | 2 +- lib/technical_analysis/indicators/macd.rb | 2 +- lib/technical_analysis/indicators/mi.rb | 2 +- lib/technical_analysis/indicators/sr.rb | 1 + 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 16e9bd7..1157a83 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -26,12 +26,12 @@ def self.min_data_size(period: 20, **params) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the BB - # @param standard_deviations [Integer] The given standard deviations to calculate the upper and lower bands of the BB + # @param standard_deviations [Float] The given standard deviations to calculate the upper and lower bands of the BB # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) period = period.to_i - standard_deviations = standard_deviations.to_i + standard_deviations = standard_deviations.to_f price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, period) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index ac21277..4a4115c 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -32,7 +32,7 @@ def self.min_data_size(medium_period: 26, high_period: 52, **params) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param low_period [Integer] The given period to calculate tenkan_sen (Conversion Line) # @param medium_period [Integer] The given period to calculate kijun_sen (Base Line), senkou_span_a (Leading Span A), and chikou_span (Lagging Span) - # @param high_period [Integer] The given period to calculate senkou_span_b (Leadning Span B) + # @param high_period [Integer] The given period to calculate senkou_span_b (Leading Span B) # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) low_period = low_period.to_i diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index cf1ce2a..2547828 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -27,7 +27,7 @@ def self.min_data_size(slow_period: 26, signal_period: 9, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param fast_period [Integer] The given period to calculate the fast moving EMA for MACD # @param slow_period [Integer] The given period to calculate the slow moving EMA for MACD - # @param signal_period [Integer] The given period to calculate the singal line for MACD + # @param signal_period [Integer] The given period to calculate the signal line for MACD # @param price_key [Symbol] The hash key for the price data. Default :value # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :value) diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 5a37169..8379ffd 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -26,7 +26,7 @@ def self.min_data_size(ema_period: 9, sum_period: 25) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low) # @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA - # @param period [Integer] The given period to calculate the MI + # @param sum_period [Integer] The given period to calculate the sum of EMA ratios # @return [Hash] A hash of the results with keys (:date_time, :value) def self.calculate(data, ema_period: 9, sum_period: 25) ema_period = ema_period.to_i diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 8bd356d..e78bf68 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -26,6 +26,7 @@ def self.min_data_size(period: 14, signal_period: 3) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the SR + # @param signal_period [Integer] The given period to calculate the SMA as a signal line for SR # @return [Array] Array of hashes with keys(:date_time, :value) def self.calculate(data, period: 14, signal_period: 3) period = period.to_i From 4b394dca2d00218ef9f1d939e824d65a34f9d5c2 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 17:11:20 -0500 Subject: [PATCH 17/84] Add Yard comments/documentation --- lib/technical_analysis/indicators/adi.rb | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index 189b0e6..01e2def 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,23 +1,43 @@ module TechnicalAnalysis class Adi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "adi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Accumulation/Distribution Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options [] end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -26,7 +46,14 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/Accumulation/distribution_index # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -112451134.66006838}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -135060226.53761944}, + # ] def self.calculate(data) Validation.validate_numeric_data(data, :high, :low, :close, :volume) From 384ef15505192aad4d173671a1ea94c6422b0457 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 17:12:24 -0500 Subject: [PATCH 18/84] Add Yard comments/documentation --- lib/technical_analysis/indicators/adtv.rb | 30 ++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 624eea8..085d014 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Adtv < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "adtv" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Average Daily Trading Volume" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period volume_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 22, **params) period.to_i end @@ -27,7 +47,15 @@ def self.min_data_size(period: 22, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given number of days used to calculate the ADTV # @param volume_key [Symbol] The hash key for the volume data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 49513676.36363637}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 49407791.81818182}, + # ] def self.calculate(data, period: 22, volume_key: :value) period = period.to_i volume_key = volume_key.to_sym From b6a79c32e8ce066a7031e2b7dca247d0012ebe05 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 17:12:45 -0500 Subject: [PATCH 19/84] Add Yard comments/documentation & private methods --- lib/technical_analysis/indicators/adx.rb | 48 ++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 4be4aee..96c5d26 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Adx < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "adx" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Average Directional Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i * 2 end @@ -26,7 +46,29 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the ADX - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :adx => 46.70506819299097, + # :di_neg => 33.86727845364526, + # :di_pos=>18.75156069669946 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :adx => 48.08801057392937, + # :di_neg => 35.92768510004254, + # :di_pos=>16.527665969119678 + # } + # }, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -87,7 +129,7 @@ def self.calculate(data, period: 14) output.sort_by_hash_date_time_desc end - def self.calculate_dm(current_price, prev_price) + private_class_method def self.calculate_dm(current_price, prev_price) if current_price[:high] - prev_price[:high] > prev_price[:low] - current_price[:low] dm_pos = [(current_price[:high] - prev_price[:high]), 0].max dm_neg = 0 @@ -102,7 +144,7 @@ def self.calculate_dm(current_price, prev_price) [dm_pos, dm_neg] end - def self.smooth_periodic_values(period, periodic_values, smoothed_values) + private_class_method def self.smooth_periodic_values(period, periodic_values, smoothed_values) if smoothed_values.empty? tr_period = periodic_values.map { |pv| pv[:tr] }.sum dm_pos_period = periodic_values.map { |pv| pv[:dm_pos] }.sum From 590027ea5675a59696e69db99b705eaa7f032737 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 17:13:22 -0500 Subject: [PATCH 20/84] Update macd min_data_size --- lib/technical_analysis/indicators/macd.rb | 4 ++-- spec/technical_analysis/indicators/macd_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 2547828..b044d30 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -18,7 +18,7 @@ def self.validate_options(options) end def self.min_data_size(slow_period: 26, signal_period: 9, **params) - slow_period.to_i + signal_period.to_i + slow_period.to_i + signal_period.to_i - 1 end # Calculates the moving average convergence divergence (MACD) for the data over the given period @@ -36,7 +36,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri signal_period = signal_period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, slow_period + signal_period) + Validation.validate_length(data, slow_period + signal_period - 1) data = data.sort_by_hash_date_time_asc diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb index 2ce42d0..93baed1 100644 --- a/spec/technical_analysis/indicators/macd_spec.rb +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -78,7 +78,7 @@ it 'Calculates minimum data size' do options = { fast_period: 12, slow_period: 24, signal_period: 10, price_key: :close } - expect(indicator.min_data_size(options)).to eq(34) + expect(indicator.min_data_size(options)).to eq(33) end end end From 40d4fd8af09ff1ec6d197c10a66fb83e57adb6a6 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 17:41:37 -0500 Subject: [PATCH 21/84] Add Yard comments/documentation - ao - atr - bb - cci - cmf - cr - dc - dlr - dpo - dr - eom - evm --- lib/technical_analysis/indicators/ao.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/atr.rb | 29 +++++++++++++++- lib/technical_analysis/indicators/bb.rb | 44 +++++++++++++++++++++++- lib/technical_analysis/indicators/cci.rb | 33 ++++++++++++++++-- lib/technical_analysis/indicators/cmf.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/cr.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/dc.rb | 42 +++++++++++++++++++++- lib/technical_analysis/indicators/dlr.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/dpo.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/dr.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/eom.rb | 30 +++++++++++++++- lib/technical_analysis/indicators/evm.rb | 3 ++ 12 files changed, 349 insertions(+), 12 deletions(-) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 82ece58..24751b6 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Ao < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "ao" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Awesome Oscillator" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(short_period long_period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(long_period: 34, **params) long_period.to_i end @@ -27,7 +47,15 @@ def self.min_data_size(long_period: 34, **params) # @param data [Array] Array of hashes with keys (:date_time, :high, :low) # @param short_period [Integer] The given period to calculate the short period SMA # @param long_period [Integer] The given period to calculate the long period SMA - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -17.518757058823525}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -17.8071908823529}, + # ] def self.calculate(data, short_period: 5, long_period: 34) short_period = short_period.to_i long_period = long_period.to_i diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 0a0ce24..a53c3b4 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -1,22 +1,41 @@ module TechnicalAnalysis class Atr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "atr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Average True Range" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i + 1 end @@ -26,7 +45,15 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the ATR - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 6.103013600253306}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 6.195553107965099}, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 1157a83..6d9e0c5 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Bb < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "bb" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Bollinger Bands" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period standard_deviations price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 20, **params) period.to_i end @@ -28,7 +48,29 @@ def self.min_data_size(period: 20, **params) # @param period [Integer] The given period to calculate the BB # @param standard_deviations [Float] The given standard deviations to calculate the upper and lower bands of the BB # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :lower_band => 141.02036711220762, + # :middle_band => 157.35499999999996, + # :upper_band => 173.6896328877923 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value=> { + # :lower_band => 141.07714470666247, + # :middle_band => 158.1695, + # :upper_band => 175.26185529333753 + # } + # }, + # ] def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) period = period.to_i standard_deviations = standard_deviations.to_f diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 22ad548..d20b3eb 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Cci < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "cci" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Commodity Channel Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period constant) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 20, **params) period.to_i end @@ -26,8 +46,17 @@ def self.min_data_size(period: 20, **params) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the CCI - # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of CCI values would fall between −100 and +100 - # @return [Hash] A hash of the results with keys (:date_time, :value) + # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of + # CCI values would fall between −100 and +100 + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -48.14847062019609}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -72.7408611895969}, + # ] def self.calculate(data, period: 20, constant: 0.015) period = period.to_i constant = constant.to_f diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 15d6715..761a8cb 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Cmf < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "cmf" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Chaikin Money Flow" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 20) period.to_i end @@ -26,7 +46,15 @@ def self.min_data_size(period: 20) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the CMF - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.14148236474171028}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.10900349402409147}, + # ] def self.calculate(data, period: 20) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index ca80133..9a3e2ce 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Cr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "cr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Cumulative Return" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.3242385507118614}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.33552254595142594}, + # ] def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 72addd3..ca6a433 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Dc < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "dc" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Donchian Channel" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 20, **params) period.to_i end @@ -27,7 +47,27 @@ def self.min_data_size(period: 20, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the DC # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :lower_bound => 142.19, + # :upper_bound => 170.95 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :lower_bound => 142.19, + # :upper_bound => 170.95 + # } + # }, + # ] def self.calculate(data, period: 20, price_key: :value) period = period.to_i price_key = price_key.to_sym diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index c695730..78980c8 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Dlr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "dlr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Daily Log Return" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -27,7 +47,15 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 0.01683917971506794}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 0.01888364670315034}, + # ] def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index dd4526e..1297e1e 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Dpo < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "dpo" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Detrended Price Oscillator" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 20, **params) period.to_i + (period.to_i / 2) end @@ -27,7 +47,15 @@ def self.min_data_size(period: 20, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -15.774999999999977}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -19.607999999999976}, + # ] def self.calculate(data, period: 20, price_key: :value) period = period.to_i price_key = price_key.to_sym diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index f01b890..48e20bb 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Dr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "dr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Daily Return" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 0.01698175787728018}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 0.019063070371121427}, + # ] def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index e2c9cd7..5724144 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Eom < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "eom" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Ease of Movement" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i + 1 end @@ -26,7 +46,15 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) # @param period [Integer] The given period to calculate the Eom / EVM - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -6.497226050937367}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -7.7025655861800235}, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index 032ac57..22d73bc 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -1,6 +1,9 @@ module TechnicalAnalysis class Evm < Eom + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "evm" end From 942d68d25c284615e5be4d4887cf6adac5a86b6a Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 7 Feb 2019 18:21:27 -0500 Subject: [PATCH 22/84] Add Yard comments/documentation - fi - ichimoku - indicator - kc - kst - macd - mfi - mi - nvi - obv - obv_mean - rsi - sma - sr - trix - tsi - uo - vi - vpt - wr --- lib/technical_analysis/indicators/fi.rb | 30 +++++++++++- lib/technical_analysis/indicators/ichimoku.rb | 48 ++++++++++++++++++- .../indicators/indicator.rb | 39 +++++++++++++-- lib/technical_analysis/indicators/kc.rb | 44 ++++++++++++++++- lib/technical_analysis/indicators/kst.rb | 32 ++++++++++++- lib/technical_analysis/indicators/macd.rb | 44 ++++++++++++++++- lib/technical_analysis/indicators/mfi.rb | 30 +++++++++++- lib/technical_analysis/indicators/mi.rb | 30 +++++++++++- lib/technical_analysis/indicators/nvi.rb | 30 +++++++++++- lib/technical_analysis/indicators/obv.rb | 30 +++++++++++- lib/technical_analysis/indicators/obv_mean.rb | 30 +++++++++++- lib/technical_analysis/indicators/rsi.rb | 30 +++++++++++- lib/technical_analysis/indicators/sma.rb | 30 +++++++++++- lib/technical_analysis/indicators/sr.rb | 42 +++++++++++++++- lib/technical_analysis/indicators/trix.rb | 30 +++++++++++- lib/technical_analysis/indicators/tsi.rb | 32 ++++++++++++- lib/technical_analysis/indicators/uo.rb | 32 ++++++++++++- lib/technical_analysis/indicators/vi.rb | 42 +++++++++++++++- lib/technical_analysis/indicators/vpt.rb | 30 +++++++++++- lib/technical_analysis/indicators/wr.rb | 30 +++++++++++- 20 files changed, 658 insertions(+), 27 deletions(-) diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 2cd161f..ad9ff32 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -1,23 +1,43 @@ module TechnicalAnalysis class Fi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "fi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Force Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options [] end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 2 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/Force_index # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 115287987.2000001}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 114556606.19999972}, + # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, 2) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 4a4115c..eecd1ef 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Ichimoku < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "ichimoku" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Ichimoku Kinko Hyo" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(low_period medium_period high_period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(medium_period: 26, high_period: 52, **params) high_period.to_i + medium_period.to_i - 2 end @@ -33,7 +53,33 @@ def self.min_data_size(medium_period: 26, high_period: 52, **params) # @param low_period [Integer] The given period to calculate tenkan_sen (Conversion Line) # @param medium_period [Integer] The given period to calculate kijun_sen (Base Line), senkou_span_a (Leading Span A), and chikou_span (Lagging Span) # @param high_period [Integer] The given period to calculate senkou_span_b (Leading Span B) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :chikou_span => 157.17, + # :kijun_sen => 150.68, + # :senkou_span_a => 155.9775, + # :senkou_span_b => 165.765, + # :tenkan_sen => 150.215 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :chikou_span => 146.83, + # :kijun_sen => 150.68, + # :senkou_span_a => 156.965, + # :senkou_span_b => 165.765, + # :tenkan_sen => 147.81 + # } + # }, + # ] def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) low_period = low_period.to_i medium_period = medium_period.to_i diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 2b429f8..68d0c3d 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -10,6 +10,9 @@ class Indicator :validate_options, ].freeze + # Returns an array of TechnicalAnalsyis modules + # + # @return [Array] A list of TechnicalAnalysis::Class def self.roster [ TechnicalAnalysis::Adi, @@ -50,6 +53,10 @@ def self.roster end # Finds the applicable indicator and returns an instance + # + # @param indicator_symbol [String] Downcased string of the indicator symbol + # + # @return TechnicalAnalysis::ClassName def self.find(indicator_symbol) self.roster.each do |indicator| return indicator if indicator.indicator_symbol == indicator_symbol @@ -59,6 +66,13 @@ def self.find(indicator_symbol) end # Find the applicable indicator and looks up the value + # + # @param indicator_symbol [String] Downcased string of the indicator symbol + # @param data [Array] Array of hashes of price data to perform calcualtion on + # @param calculation [Symbol] The calculation to be performed on the requested indicator and params + # @param options [Hash] A hash containing options for the requested calculation + # + # @return Returns the requested calculation def self.calculate(indicator_symbol, data, calculation, options={}) return nil unless CALCULATIONS.include? calculation @@ -76,30 +90,45 @@ def self.calculate(indicator_symbol, data, calculation, options={}) end end - # Calculates the minimum data size for an indicator + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(indicator_symbol, options) raise "#{self.name} did not implement min_data_size" nil end - # Validates the options for the indicator + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) raise "#{self.name} did not implement validate_options" false end - # Returns the valid options for the indicator + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options raise "#{self.name} did not implement valid_options" [] end - # Returns the symbol string of the indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol raise "#{self.name} did not implement indicator_symbol" end - # Returns the name string of the indicator + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name raise "#{self.name} did not implement indicator_name" end diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 91888b4..0015369 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Kc < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "kc" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Keltner Channel" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 10) period.to_i end @@ -26,7 +46,29 @@ def self.min_data_size(period: 10) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the KC - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :lower_band => 147.1630066666667, + # :middle_band => 151.9909966666667, + # :upper_band => 156.8189866666667 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :lower_band => 146.74034, + # :middle_band => 151.57433, + # :upper_band => 156.40832 + # } + # } + # ] def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index eea6ae7..3ebcb71 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Kst < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "kst" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Know Sure Thing" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period roc1 roc2 roc3 roc4 sma1 sma2 sma3 sma4 price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(roc4: 30, sma4: 15, **params) roc4.to_i + sma4.to_i - 1 end @@ -34,7 +54,15 @@ def self.min_data_size(roc4: 30, sma4: 15, **params) # @param sma3 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA3 # @param sma4 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA4 # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -140.9140022298261}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -148.9261153101682}, + # ] def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value) roc1 = roc1.to_i roc2 = roc2.to_i @@ -69,7 +97,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: output.sort_by_hash_date_time_desc end - def self.calculate_rcma(data, index, price_key, roc, sma) + private_class_method def self.calculate_rcma(data, index, price_key, roc, sma) roc_data = [] index_range = (index - sma + 1)..index diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index b044d30..657450f 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Macd < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "macd" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Moving Average Convergence Divergence" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(fast_period slow_period signal_period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(slow_period: 26, signal_period: 9, **params) slow_period.to_i + signal_period.to_i - 1 end @@ -29,7 +49,29 @@ def self.min_data_size(slow_period: 26, signal_period: 9, **params) # @param slow_period [Integer] The given period to calculate the slow moving EMA for MACD # @param signal_period [Integer] The given period to calculate the signal line for MACD # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :macd_histogram => 0.8762597178840466, + # :macd_line => -8.126908458242355, + # :signal_line => -9.003168176126401 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :macd_histogram => 0.4770591535283888, + # :macd_line => -8.745173952069024, + # :signal_line => -9.222233105597413 + # } + # } + # ] def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :value) fast_period = fast_period.to_i slow_period = slow_period.to_i diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index df7cce4..7774428 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Mfi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "mfi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Money Flow Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i + 1 end @@ -26,7 +46,15 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the MFI - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 50.72343663578981}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 50.1757147722236}, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 8379ffd..1922363 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Mi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "mi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Mass Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(ema_period sum_period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(ema_period: 9, sum_period: 25) (ema_period.to_i * 2) + sum_period.to_i - 2 end @@ -27,7 +47,15 @@ def self.min_data_size(ema_period: 9, sum_period: 25) # @param data [Array] Array of hashes with keys (:date_time, :high, :low) # @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA # @param sum_period [Integer] The given period to calculate the sum of EMA ratios - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 24.77520633216394}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 24.80084030980544}, + # ] def self.calculate(data, ema_period: 9, sum_period: 25) ema_period = ema_period.to_i sum_period = sum_period.to_i diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index dfbfadc..f8784b4 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -1,23 +1,43 @@ module TechnicalAnalysis class Nvi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "nvi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Negative Volume Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options [] end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/Negative_volume_index # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 1002.8410612825647}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 1002.8410612825647}, + # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, 1) diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 7f80fa4..dc720eb 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -1,23 +1,43 @@ module TechnicalAnalysis class Obv < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "obv" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "On-balance Volume" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options [] end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 1 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/On-balance_volume # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -591085010}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -636119380}, + # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, 1) diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 4342fc3..1b3585d 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class ObvMean < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "obv_mean" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "On-balance Volume Mean" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 10) period.to_i end @@ -26,7 +46,15 @@ def self.min_data_size(period: 10) # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @param period [Integer] The given period to calculate the OBV mean - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -642606913.0}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -654187384.0}, + # ] def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :close, :volume) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 784af68..325f98b 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Rsi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "rsi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Relative Strength Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14, **params) period.to_i + 1 end @@ -27,7 +47,15 @@ def self.min_data_size(period: 14, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the RSI # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 41.01572095202713}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 38.100858593859655}, + # ] def self.calculate(data, period: 14, price_key: :value) period = period.to_i price_key = price_key.to_sym diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 7202849..853c4c5 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Sma < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "sma" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Simple Moving Average" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 30, **params) period.to_i end @@ -27,7 +47,15 @@ def self.min_data_size(period: 30, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 148.488}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 149.41}, + # ] def self.calculate(data, period: 30, price_key: :value) period = period.to_i price_key = price_key.to_sym diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index e78bf68..2838191 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Sr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "sr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Stochastic Oscillator" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period signal_period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14, signal_period: 3) period.to_i + signal_period.to_i - 1 end @@ -27,7 +47,27 @@ def self.min_data_size(period: 14, signal_period: 3) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the SR # @param signal_period [Integer] The given period to calculate the SMA as a signal line for SR - # @return [Array] Array of hashes with keys(:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :sr => 44.44007858546172, + # :sr_signal => 33.739408752366685 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :sr => 34.27340383862123, + # :sr_signal => 26.631612985573174 + # } + # }, + # ] def self.calculate(data, period: 14, signal_period: 3) period = period.to_i signal_period = signal_period.to_i diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 7f95a2c..9e91725 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Trix < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "trix" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Triple Exponential Average" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 15, **params) (period.to_i * 3) - 1 end @@ -27,7 +47,15 @@ def self.min_data_size(period: 15, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the EMA for Trix # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.007522826289174942}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.007639218329257057}, + # ] def self.calculate(data, period: 15, price_key: :value) period = period.to_i price_key = price_key.to_sym diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 1df5a2d..82b7884 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Tsi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "tsi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "True Strength Index" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(low_period high_period price_key) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(low_period: 13, high_period: 25, **params) low_period.to_i + high_period.to_i end @@ -28,7 +48,15 @@ def self.min_data_size(low_period: 13, high_period: 25, **params) # @param high_period [Integer] The given high period to calculate the EMA # @param low_period [Integer] The given low period to calculate the EMA # @param price_key [Symbol] The hash key for the price data. Default :value - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -28.91017661103889}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -30.97413963420104}, + # ] def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) low_period = low_period.to_i high_period = high_period.to_i @@ -75,7 +103,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) output.sort_by_hash_date_time_desc end - def self.process_ema(current_value, data, multiplier, period, store) + private_class_method def self.process_ema(current_value, data, multiplier, period, store) if store.empty? value = data.map { |d| d[:value] }.average abs_value = data.map { |d| d[:abs_value] }.average diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index b854866..5bc5a17 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Uo < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "uo" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Ultimate Oscillator" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(short_period medium_period long_period short_weight medium_weight long_weight) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(long_period: 28, **params) long_period.to_i + 1 end @@ -31,7 +51,15 @@ def self.min_data_size(long_period: 28, **params) # @param short_weight [Float] Weight of short Buying Pressure average for UO # @param medium_weight [Float] Weight of medium Buying Pressure average for UO # @param long_weight [Float] Weight of long Buying Pressure average for UO - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => 47.28872762629681}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => 44.828908983561035}, + # ] def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) short_period = short_period.to_i medium_period = medium_period.to_i @@ -75,7 +103,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh output.sort_by_hash_date_time_desc end - def self.calculate_average(period, data) + private_class_method def self.calculate_average(period, data) buying_pressures_sum = data.last(period).map { |d| d[:buying_pressure] }.sum true_ranges_sum = data.last(period).map { |d| d[:true_range] }.sum diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 3c6550f..fbcb6b1 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Vi < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "vi" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Vortex Indicator" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i + 1 end @@ -26,7 +46,27 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the VI - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # { + # :date_time => "2019-01-09T00:00:00.000Z", + # :value => { + # :negative_vi => 0.9777149447928525, + # :positive_vi => 0.8609629970246735 + # } + # }, + # { + # :date_time => "2019-01-08T00:00:00.000Z", + # :value => { + # :negative_vi => 1.0113586362578701, + # :positive_vi => 0.8600571901821686 + # } + # }, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index a15df46..1e2bd00 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -1,23 +1,43 @@ module TechnicalAnalysis class Vpt < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "vpt" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Volume-price Trend" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options [] end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(**params) 2 end @@ -26,7 +46,15 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/Volume%E2%80%93price_trend # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -27383899.78109331}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -28148662.548589166}, + # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, 2) diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 44fcf88..8c6b536 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -1,22 +1,42 @@ module TechnicalAnalysis class Wr < Indicator + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator def self.indicator_symbol "wr" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator def self.indicator_name "Williams %R" end + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options %i(period) end + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options vare valid or raises an error if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided def self.min_data_size(period: 14) period.to_i end @@ -26,7 +46,15 @@ def self.min_data_size(period: 14) # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given look-back period to calculate the WR - # @return [Hash] A hash of the results with keys (:date_time, :value) + # + # @return [Array] + # + # An array of hashes with keys (:date_time, :value). Example output: + # + # [ + # {:date_time => "2019-01-09T00:00:00.000Z", :value => -55.55992141453828}, + # {:date_time => "2019-01-08T00:00:00.000Z", :value => -65.72659616137877}, + # ] def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) From 06e96e03c63da6caaac50e30d34405c21ca501b4 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 8 Feb 2019 11:27:55 -0500 Subject: [PATCH 23/84] Update min_data_size for obv_mean and ichimoku --- lib/technical_analysis/indicators/ichimoku.rb | 4 ++-- lib/technical_analysis/indicators/obv_mean.rb | 4 ++-- spec/technical_analysis/indicators/ichimoku_spec.rb | 2 +- spec/technical_analysis/indicators/obv_mean_spec.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index eecd1ef..70f075f 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -38,7 +38,7 @@ def self.validate_options(options) # @return [Integer] Returns the minimum number of observations needed to calculate the technical # indicator based on the options provided def self.min_data_size(medium_period: 26, high_period: 52, **params) - high_period.to_i + medium_period.to_i - 2 + high_period.to_i + medium_period.to_i - 1 end # Calculates the 5 points of Ichimoku Kinko Hyo (Ichimoku) for the data over the given period @@ -85,7 +85,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) medium_period = medium_period.to_i high_period = high_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, high_period + medium_period - 2) + Validation.validate_length(data, high_period + medium_period - 1) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 1b3585d..f1b7cbf 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -38,7 +38,7 @@ def self.validate_options(options) # @return [Integer] Returns the minimum number of observations needed to calculate the technical # indicator based on the options provided def self.min_data_size(period: 10) - period.to_i + period.to_i + 1 end # Calculates the on-balance volume mean (OBV mean) for the data over the given period @@ -58,7 +58,7 @@ def self.min_data_size(period: 10) def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, period) + Validation.validate_length(data, period + 1) data = data.sort_by_hash_date_time_asc diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb index 36d5637..0653c11 100644 --- a/spec/technical_analysis/indicators/ichimoku_spec.rb +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -87,7 +87,7 @@ it 'Calculates minimum data size' do options = { medium_period: 4, high_period: 10 } - expect(indicator.min_data_size(options)).to eq(12) + expect(indicator.min_data_size(options)).to eq(13) end end end diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb index 05ae85d..1f4d52b 100644 --- a/spec/technical_analysis/indicators/obv_mean_spec.rb +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -101,7 +101,7 @@ it 'Calculates minimum data size' do options = { period: 4 } - expect(indicator.min_data_size(options)).to eq(4) + expect(indicator.min_data_size(options)).to eq(5) end end end From 1b19e4b9d6d5e2b2df2ab63b7114ea1798050666 Mon Sep 17 00:00:00 2001 From: Alex Date: Fri, 8 Feb 2019 11:33:00 -0500 Subject: [PATCH 24/84] Make helper methods private --- lib/technical_analysis/indicators/ichimoku.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 70f075f..72a8719 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -118,15 +118,15 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) output.sort_by_hash_date_time_desc end - def self.lowest_low(prices) + private_class_method def self.lowest_low(prices) prices.map { |price| price[:low] }.min end - def self.highest_high(prices) + private_class_method def self.highest_high(prices) prices.map { |price| price[:high] }.max end - def self.calculate_midpoint(index, period, data) + private_class_method def self.calculate_midpoint(index, period, data) period_range = ((index - (period - 1))..index) period_data = data[period_range] lowest_low = lowest_low(period_data) @@ -135,7 +135,7 @@ def self.calculate_midpoint(index, period, data) ((highest_high + lowest_low) / 2.0) end - def self.calculate_senkou_span_a(index, low_period, medium_period, data) + private_class_method def self.calculate_senkou_span_a(index, low_period, medium_period, data) mp_ago_index = (index - (medium_period - 1)) tenkan_sen_mp_ago = calculate_midpoint(mp_ago_index, low_period, data) @@ -144,13 +144,13 @@ def self.calculate_senkou_span_a(index, low_period, medium_period, data) ((tenkan_sen_mp_ago + kinjun_sen_mp_ago) / 2.0) end - def self.calculate_senkou_span_b(index, medium_period, high_period, data) + private_class_method def self.calculate_senkou_span_b(index, medium_period, high_period, data) mp_ago_index = (index - (medium_period - 1)) calculate_midpoint(mp_ago_index, high_period, data) end - def self.calculate_chikou_span(index, medium_period, data) + private_class_method def self.calculate_chikou_span(index, medium_period, data) mp_ago_index = (index - (medium_period - 1)) data[mp_ago_index][:close] From b4262409c092fa62a577cb387afd7b166946d3bd Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 11 Feb 2019 14:15:59 -0500 Subject: [PATCH 25/84] Update yard comments --- lib/technical_analysis/indicators/adi.rb | 2 +- lib/technical_analysis/indicators/adtv.rb | 2 +- lib/technical_analysis/indicators/adx.rb | 4 ++-- lib/technical_analysis/indicators/ao.rb | 2 +- lib/technical_analysis/indicators/atr.rb | 2 +- lib/technical_analysis/indicators/bb.rb | 2 +- lib/technical_analysis/indicators/cci.rb | 2 +- lib/technical_analysis/indicators/cmf.rb | 2 +- lib/technical_analysis/indicators/cr.rb | 2 +- lib/technical_analysis/indicators/dc.rb | 2 +- lib/technical_analysis/indicators/dlr.rb | 2 +- lib/technical_analysis/indicators/dpo.rb | 2 +- lib/technical_analysis/indicators/dr.rb | 2 +- lib/technical_analysis/indicators/eom.rb | 2 +- lib/technical_analysis/indicators/fi.rb | 2 +- lib/technical_analysis/indicators/ichimoku.rb | 2 +- lib/technical_analysis/indicators/indicator.rb | 2 +- lib/technical_analysis/indicators/kc.rb | 2 +- lib/technical_analysis/indicators/kst.rb | 2 +- lib/technical_analysis/indicators/macd.rb | 2 +- lib/technical_analysis/indicators/mfi.rb | 2 +- lib/technical_analysis/indicators/mi.rb | 2 +- lib/technical_analysis/indicators/nvi.rb | 2 +- lib/technical_analysis/indicators/obv.rb | 2 +- lib/technical_analysis/indicators/obv_mean.rb | 2 +- lib/technical_analysis/indicators/rsi.rb | 2 +- lib/technical_analysis/indicators/sma.rb | 2 +- lib/technical_analysis/indicators/sr.rb | 2 +- lib/technical_analysis/indicators/trix.rb | 2 +- lib/technical_analysis/indicators/tsi.rb | 2 +- lib/technical_analysis/indicators/uo.rb | 2 +- lib/technical_analysis/indicators/vi.rb | 2 +- lib/technical_analysis/indicators/vpt.rb | 2 +- lib/technical_analysis/indicators/wr.rb | 2 +- 34 files changed, 35 insertions(+), 35 deletions(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index 01e2def..af3922a 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 085d014..7adc179 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 96c5d26..b73dd3a 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end @@ -44,7 +44,7 @@ def self.min_data_size(period: 14) # Calculates the average directional index (ADX) for the data over the given period # https://en.wikipedia.org/wiki/Average_directional_movement_index # - # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the ADX # # @return [Array] diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 24751b6..0e1f0a9 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index a53c3b4..d15817e 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 6d9e0c5..c5fdf51 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index d20b3eb..dd784a1 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 761a8cb..a25c246 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 9a3e2ce..f90c8bb 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index ca6a433..f8ff786 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 78980c8..568b194 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 1297e1e..ec20c92 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 48e20bb..8148907 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 5724144..f686364 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index ad9ff32..a19f245 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 72a8719..afd6a84 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 68d0c3d..84036bc 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -105,7 +105,7 @@ def self.min_data_size(indicator_symbol, options) # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) raise "#{self.name} did not implement validate_options" false diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 0015369..241ce39 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 3ebcb71..c2aa619 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 657450f..4230364 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 7774428..1c4b24c 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 1922363..ec17362 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index f8784b4..d20585a 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index dc720eb..c7529b4 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index f1b7cbf..fc84b4b 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 325f98b..abc3fd2 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 853c4c5..1071681 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 2838191..71e8ede 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 9e91725..4b43ff3 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 82b7884..c459df7 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index 5bc5a17..f7beebd 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index fbcb6b1..a80c1e6 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index 1e2bd00..acb929e 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) return true if options == {} raise Validation::ValidationError.new "This indicator doesn't accept any options." diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 8c6b536..b8ba2ef 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -26,7 +26,7 @@ def self.valid_options # # @param options [Hash] The options for the technical indicator to be validated # - # @return [Boolean] Returns true if options vare valid or raises an error if they're not + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not def self.validate_options(options) Validation.validate_options(options, valid_options) end From 0c1a154f8643ebb3ff578c2cd0e3f179914c6a1f Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 11 Feb 2019 14:30:52 -0500 Subject: [PATCH 26/84] Update data size validator in calculate - Use min_data_size method when validating data sizes in calculate --- lib/technical_analysis/indicators/adtv.rb | 2 +- lib/technical_analysis/indicators/adx.rb | 4 ++-- lib/technical_analysis/indicators/ao.rb | 2 +- lib/technical_analysis/indicators/atr.rb | 2 +- lib/technical_analysis/indicators/bb.rb | 2 +- lib/technical_analysis/indicators/cci.rb | 2 +- lib/technical_analysis/indicators/cmf.rb | 2 +- lib/technical_analysis/indicators/cr.rb | 2 +- lib/technical_analysis/indicators/dc.rb | 2 +- lib/technical_analysis/indicators/dlr.rb | 2 +- lib/technical_analysis/indicators/dpo.rb | 2 +- lib/technical_analysis/indicators/dr.rb | 2 +- lib/technical_analysis/indicators/eom.rb | 2 +- lib/technical_analysis/indicators/fi.rb | 2 +- lib/technical_analysis/indicators/ichimoku.rb | 2 +- lib/technical_analysis/indicators/kc.rb | 2 +- lib/technical_analysis/indicators/kst.rb | 2 +- lib/technical_analysis/indicators/macd.rb | 2 +- lib/technical_analysis/indicators/mfi.rb | 2 +- lib/technical_analysis/indicators/mi.rb | 2 +- lib/technical_analysis/indicators/nvi.rb | 2 +- lib/technical_analysis/indicators/obv.rb | 2 +- lib/technical_analysis/indicators/obv_mean.rb | 2 +- lib/technical_analysis/indicators/rsi.rb | 2 +- lib/technical_analysis/indicators/sma.rb | 2 +- lib/technical_analysis/indicators/sr.rb | 2 +- lib/technical_analysis/indicators/trix.rb | 2 +- lib/technical_analysis/indicators/tsi.rb | 2 +- lib/technical_analysis/indicators/uo.rb | 2 +- lib/technical_analysis/indicators/vi.rb | 2 +- lib/technical_analysis/indicators/vpt.rb | 2 +- lib/technical_analysis/indicators/wr.rb | 2 +- 32 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 7adc179..a3d6bf8 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 22, volume_key: :value) period = period.to_i volume_key = volume_key.to_sym Validation.validate_numeric_data(data, volume_key) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index b73dd3a..014a173 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -72,10 +72,10 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period * 2) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc - + dx_values = [] output = [] periodic_values = [] diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 0e1f0a9..5b6c855 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -60,7 +60,7 @@ def self.calculate(data, short_period: 5, long_period: 34) short_period = short_period.to_i long_period = long_period.to_i Validation.validate_numeric_data(data, :high, :low) - Validation.validate_length(data, long_period) + Validation.validate_length(data, min_data_size(long_period: long_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index d15817e..0fdba2b 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -57,7 +57,7 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index c5fdf51..3b5e25c 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -76,7 +76,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) standard_deviations = standard_deviations.to_f price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index dd784a1..12cff60 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -61,7 +61,7 @@ def self.calculate(data, period: 20, constant: 0.015) period = period.to_i constant = constant.to_f Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index a25c246..ff30a9f 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -58,7 +58,7 @@ def self.min_data_size(period: 20) def self.calculate(data, period: 20) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index f90c8bb..8ce4c46 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -58,7 +58,7 @@ def self.min_data_size(**params) def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, 1) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index f8ff786..573fb99 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -72,7 +72,7 @@ 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, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 568b194..3468bf3 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -59,7 +59,7 @@ def self.min_data_size(**params) def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, 1) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index ec20c92..d3e228d 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -60,7 +60,7 @@ 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, period + (period / 2)) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 8148907..8666dc3 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -58,7 +58,7 @@ def self.min_data_size(**params) def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, 1) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index f686364..f64d7b4 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -58,7 +58,7 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index a19f245..5e2f233 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -57,7 +57,7 @@ def self.min_data_size(**params) # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, 2) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index afd6a84..2fdb851 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -85,7 +85,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) medium_period = medium_period.to_i high_period = high_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, high_period + medium_period - 1) + Validation.validate_length(data, min_data_size(high_period: high_period, medium_period: medium_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 241ce39..9112bfe 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -72,7 +72,7 @@ def self.min_data_size(period: 10) def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index c2aa619..478d612 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -74,7 +74,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: sma4 = sma4.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, roc4 + sma4 - 1) + Validation.validate_length(data, min_data_size(roc4: roc4, sma4: sma4)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 4230364..d67fea2 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -78,7 +78,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri signal_period = signal_period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, slow_period + signal_period - 1) + Validation.validate_length(data, min_data_size(slow_period: slow_period, signal_period: signal_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 1c4b24c..9b62cff 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -58,7 +58,7 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index ec17362..b315cde 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -60,7 +60,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) ema_period = ema_period.to_i sum_period = sum_period.to_i Validation.validate_numeric_data(data, :high, :low) - Validation.validate_length(data, (ema_period * 2) + sum_period - 2) + Validation.validate_length(data, min_data_size(ema_period: ema_period, sum_period: sum_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index d20585a..35d15a6 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -57,7 +57,7 @@ def self.min_data_size(**params) # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, 1) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index c7529b4..e84eb81 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -57,7 +57,7 @@ def self.min_data_size(**params) # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, 1) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index fc84b4b..6606a30 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -58,7 +58,7 @@ def self.min_data_size(period: 10) def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index abc3fd2..ac4f1e9 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 14, price_key: :value) period = period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 1071681..bae9c5d 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 30, price_key: :value) period = period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 71e8ede..bffe16d 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -72,7 +72,7 @@ def self.calculate(data, period: 14, signal_period: 3) period = period.to_i signal_period = signal_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period + signal_period - 1) + Validation.validate_length(data, min_data_size(period: period, signal_period: signal_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 4b43ff3..37faaf6 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 15, price_key: :value) period = period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, ((period * 3) - 1)) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index c459df7..62d3ceb 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -62,7 +62,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) high_period = high_period.to_i price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) - Validation.validate_length(data, low_period + high_period) + Validation.validate_length(data, min_data_size(low_period: low_period, high_period: high_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index f7beebd..b1081dc 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -68,7 +68,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh medium_weight = medium_weight.to_f long_weight = long_weight.to_f Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, long_period + 1) + Validation.validate_length(data, min_data_size(long_period: long_period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index a80c1e6..5a78e14 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -70,7 +70,7 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period + 1) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index acb929e..be04896 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -57,7 +57,7 @@ def self.min_data_size(**params) # ] def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) - Validation.validate_length(data, 2) + Validation.validate_length(data, min_data_size({})) data = data.sort_by_hash_date_time_asc diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index b8ba2ef..6c92a07 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -58,7 +58,7 @@ def self.min_data_size(period: 14) def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) - Validation.validate_length(data, period) + Validation.validate_length(data, min_data_size(period: period)) data = data.sort_by_hash_date_time_asc From f1ebb5cb157a4cbc16c1134324412f59b950db47 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 11 Feb 2019 16:30:54 -0500 Subject: [PATCH 27/84] Update yard comments --- lib/technical_analysis/indicators/adx.rb | 8 ++++---- lib/technical_analysis/indicators/atr.rb | 3 ++- lib/technical_analysis/indicators/bb.rb | 8 ++++---- lib/technical_analysis/indicators/eom.rb | 2 +- lib/technical_analysis/indicators/ichimoku.rb | 12 ++++++------ lib/technical_analysis/indicators/kc.rb | 8 ++++---- lib/technical_analysis/indicators/kst.rb | 2 +- lib/technical_analysis/indicators/macd.rb | 8 ++++---- lib/technical_analysis/indicators/sr.rb | 4 ++-- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 014a173..dab2e80 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -55,17 +55,17 @@ def self.min_data_size(period: 14) # { # :date_time => "2019-01-09T00:00:00.000Z", # :value => { - # :adx => 46.70506819299097, + # :adx => 46.70506819299097, # :di_neg => 33.86727845364526, - # :di_pos=>18.75156069669946 + # :di_pos => 18.75156069669946 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value => { - # :adx => 48.08801057392937, + # :adx => 48.08801057392937, # :di_neg => 35.92768510004254, - # :di_pos=>16.527665969119678 + # :di_pos => 16.527665969119678 # } # }, # ] diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 0fdba2b..24447f4 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -31,7 +31,8 @@ def self.validate_options(options) Validation.validate_options(options, valid_options) end - # Calculates the minimum number of observations needed to calculate the technical indicator # + # Calculates the minimum number of observations needed to calculate the technical indicator + # # @param options [Hash] The options for the technical indicator # # @return [Integer] Returns the minimum number of observations needed to calculate the technical diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 3b5e25c..f0315cc 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -57,17 +57,17 @@ def self.min_data_size(period: 20, **params) # { # :date_time => "2019-01-09T00:00:00.000Z", # :value => { - # :lower_band => 141.02036711220762, + # :lower_band => 141.02036711220762, # :middle_band => 157.35499999999996, - # :upper_band => 173.6896328877923 + # :upper_band => 173.6896328877923 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value=> { - # :lower_band => 141.07714470666247, + # :lower_band => 141.07714470666247, # :middle_band => 158.1695, - # :upper_band => 175.26185529333753 + # :upper_band => 175.26185529333753 # } # }, # ] diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index f64d7b4..0f0d8f7 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -45,7 +45,7 @@ def self.min_data_size(period: 14) # https://en.wikipedia.org/wiki/Ease_of_movement # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) - # @param period [Integer] The given period to calculate the Eom / EVM + # @param period [Integer] The given period to calculate the EoM / EVM # # @return [Array] # diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 2fdb851..fa52626 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -62,21 +62,21 @@ def self.min_data_size(medium_period: 26, high_period: 52, **params) # { # :date_time => "2019-01-09T00:00:00.000Z", # :value => { - # :chikou_span => 157.17, - # :kijun_sen => 150.68, + # :chikou_span => 157.17, + # :kijun_sen => 150.68, # :senkou_span_a => 155.9775, # :senkou_span_b => 165.765, - # :tenkan_sen => 150.215 + # :tenkan_sen => 150.215 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value => { - # :chikou_span => 146.83, - # :kijun_sen => 150.68, + # :chikou_span => 146.83, + # :kijun_sen => 150.68, # :senkou_span_a => 156.965, # :senkou_span_b => 165.765, - # :tenkan_sen => 147.81 + # :tenkan_sen => 147.81 # } # }, # ] diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 9112bfe..1952e33 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -55,17 +55,17 @@ def self.min_data_size(period: 10) # { # :date_time => "2019-01-09T00:00:00.000Z", # :value => { - # :lower_band => 147.1630066666667, + # :lower_band => 147.1630066666667, # :middle_band => 151.9909966666667, - # :upper_band => 156.8189866666667 + # :upper_band => 156.8189866666667 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value => { - # :lower_band => 146.74034, + # :lower_band => 146.74034, # :middle_band => 151.57433, - # :upper_band => 156.40832 + # :upper_band => 156.40832 # } # } # ] diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 478d612..55d0ab3 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -49,7 +49,7 @@ def self.min_data_size(roc4: 30, sma4: 15, **params) # @param roc2 [Integer] The given period to calculate the rate-of-change for RCMA2 # @param roc3 [Integer] The given period to calculate the rate-of-change for RCMA3 # @param roc4 [Integer] The given period to calculate the rate-of-change for RCMA4 - # @param sma1 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA1 + # @param sma1 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA1 # @param sma2 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA2 # @param sma3 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA3 # @param sma4 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA4 diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index d67fea2..63621fd 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -59,16 +59,16 @@ def self.min_data_size(slow_period: 26, signal_period: 9, **params) # :date_time => "2019-01-09T00:00:00.000Z", # :value => { # :macd_histogram => 0.8762597178840466, - # :macd_line => -8.126908458242355, - # :signal_line => -9.003168176126401 + # :macd_line => -8.126908458242355, + # :signal_line => -9.003168176126401 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value => { # :macd_histogram => 0.4770591535283888, - # :macd_line => -8.745173952069024, - # :signal_line => -9.222233105597413 + # :macd_line => -8.745173952069024, + # :signal_line => -9.222233105597413 # } # } # ] diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index bffe16d..c4bada3 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -56,14 +56,14 @@ def self.min_data_size(period: 14, signal_period: 3) # { # :date_time => "2019-01-09T00:00:00.000Z", # :value => { - # :sr => 44.44007858546172, + # :sr => 44.44007858546172, # :sr_signal => 33.739408752366685 # } # }, # { # :date_time => "2019-01-08T00:00:00.000Z", # :value => { - # :sr => 34.27340383862123, + # :sr => 34.27340383862123, # :sr_signal => 26.631612985573174 # } # }, From a2b6923cb188fff238e8c7916bee6673d72521a3 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 16:27:41 -0500 Subject: [PATCH 28/84] Move roster and calculations to private --- lib/technical_analysis/indicators/indicator.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 84036bc..b935d1a 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -10,10 +10,12 @@ class Indicator :validate_options, ].freeze - # Returns an array of TechnicalAnalsyis modules + private_constant :CALCULATIONS + + # Returns an array of TechnicalAnalysis modules # # @return [Array] A list of TechnicalAnalysis::Class - def self.roster + private_class_method def self.roster [ TechnicalAnalysis::Adi, TechnicalAnalysis::Adtv, @@ -58,7 +60,7 @@ def self.roster # # @return TechnicalAnalysis::ClassName def self.find(indicator_symbol) - self.roster.each do |indicator| + roster.each do |indicator| return indicator if indicator.indicator_symbol == indicator_symbol end From 6af104f5d9315e73533c249fadbe5bbbfaec994a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 16:34:13 -0500 Subject: [PATCH 29/84] Update array helpers for sorting by date_time --- lib/technical_analysis/helpers/array.rb | 12 ++++-- lib/technical_analysis/indicators/adi.rb | 38 +++++++++++++------ lib/technical_analysis/indicators/adtv.rb | 37 ++++++++++++------ lib/technical_analysis/indicators/adx.rb | 4 +- lib/technical_analysis/indicators/ao.rb | 4 +- lib/technical_analysis/indicators/atr.rb | 4 +- lib/technical_analysis/indicators/bb.rb | 4 +- lib/technical_analysis/indicators/cci.rb | 4 +- lib/technical_analysis/indicators/cmf.rb | 4 +- lib/technical_analysis/indicators/cr.rb | 4 +- lib/technical_analysis/indicators/dc.rb | 4 +- lib/technical_analysis/indicators/dlr.rb | 4 +- lib/technical_analysis/indicators/dpo.rb | 4 +- lib/technical_analysis/indicators/dr.rb | 4 +- lib/technical_analysis/indicators/eom.rb | 4 +- lib/technical_analysis/indicators/fi.rb | 4 +- lib/technical_analysis/indicators/ichimoku.rb | 4 +- lib/technical_analysis/indicators/kc.rb | 4 +- lib/technical_analysis/indicators/kst.rb | 4 +- lib/technical_analysis/indicators/macd.rb | 4 +- lib/technical_analysis/indicators/mfi.rb | 4 +- lib/technical_analysis/indicators/mi.rb | 4 +- lib/technical_analysis/indicators/nvi.rb | 4 +- lib/technical_analysis/indicators/obv.rb | 4 +- lib/technical_analysis/indicators/obv_mean.rb | 4 +- lib/technical_analysis/indicators/rsi.rb | 4 +- lib/technical_analysis/indicators/sma.rb | 4 +- lib/technical_analysis/indicators/sr.rb | 4 +- lib/technical_analysis/indicators/trix.rb | 4 +- lib/technical_analysis/indicators/tsi.rb | 4 +- lib/technical_analysis/indicators/uo.rb | 4 +- lib/technical_analysis/indicators/vi.rb | 4 +- lib/technical_analysis/indicators/vpt.rb | 4 +- lib/technical_analysis/indicators/wr.rb | 4 +- 34 files changed, 123 insertions(+), 88 deletions(-) diff --git a/lib/technical_analysis/helpers/array.rb b/lib/technical_analysis/helpers/array.rb index ef33391..18f7d81 100644 --- a/lib/technical_analysis/helpers/array.rb +++ b/lib/technical_analysis/helpers/array.rb @@ -18,12 +18,16 @@ def standard_deviation Math.sqrt(self.sample_variance) end - def sort_by_hash_date_time_asc - self.sort_by { |row| row[:date_time] } + def sort_by_date_time_asc + if self.first.is_a? Hash + self.sort_by { |row| row[:date_time] } + else + self.sort_by(&:date_time) + end end - def sort_by_hash_date_time_desc - sort_by_hash_date_time_asc.reverse + def sort_by_date_time_desc + sort_by_date_time_asc.reverse end alias_method :average, :mean diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index af3922a..cfccb9d 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Accumulation/Distribution Index class Adi < Indicator # Returns the symbol of the technical indicator @@ -46,18 +47,11 @@ def self.min_data_size(**params) # https://en.wikipedia.org/wiki/Accumulation/distribution_index # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -112451134.66006838}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -135060226.53761944}, - # ] + # @return [Array] An array of AdiValue instances def self.calculate(data) Validation.validate_numeric_data(data, :high, :low, :close, :volume) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc ad = 0 ads = [] @@ -73,10 +67,32 @@ def self.calculate(data) ad = prev_ad + (clv * values[:volume]) prev_ad = ad + date_time = values[:date_time] - ads << { date_time: values[:date_time], value: ad } + ads << AdiValue.new(date_time: date_time, adi: ad) end - ads.sort_by_hash_date_time_desc + ads.sort_by_date_time_desc + end + + end + + # The value class to be returned by calculations + class AdiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the adi calculation value + attr_accessor :adi + + def initialize(date_time: nil, adi: nil) + @date_time = date_time + @adi = adi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, adi: @adi } end end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index a3d6bf8..b6b53a2 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Average Daily Trading Volume class Adtv < Indicator # Returns the symbol of the technical indicator @@ -48,21 +49,14 @@ def self.min_data_size(period: 22, **params) # @param period [Integer] The given number of days used to calculate the ADTV # @param volume_key [Symbol] The hash key for the volume data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 49513676.36363637}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 49407791.81818182}, - # ] + # @return [Array] An array of AdtvValue instances def self.calculate(data, period: 22, volume_key: :value) period = period.to_i volume_key = volume_key.to_sym Validation.validate_numeric_data(data, volume_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -70,12 +64,33 @@ def self.calculate(data, period: 22, volume_key: :value) data.each do |v| period_values << v[volume_key] if period_values.size == period - output << { date_time: v[:date_time], value: period_values.average } + output << AdtvValue.new(date_time: v[:date_time], adtv: period_values.average) period_values.shift end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc + end + + end + + # The value class to be returned by calculations + class AdtvValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the adtv calculation value + attr_accessor :adtv + + def initialize(date_time: nil, adtv: nil) + @date_time = date_time + @adtv = adtv + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, adtv: @adtv } end end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index dab2e80..e162cea 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -74,7 +74,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc dx_values = [] output = [] @@ -126,7 +126,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end private_class_method def self.calculate_dm(current_price, prev_price) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 5b6c855..96f6c78 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -62,7 +62,7 @@ def self.calculate(data, short_period: 5, long_period: 34) Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, min_data_size(long_period: long_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc midpoint_values = [] output = [] @@ -82,7 +82,7 @@ def self.calculate(data, short_period: 5, long_period: 34) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 24447f4..b692708 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -86,7 +86,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index f0315cc..ed3e376 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -78,7 +78,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -105,7 +105,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 12cff60..782ce06 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -63,7 +63,7 @@ def self.calculate(data, period: 20, constant: 0.015) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] typical_prices = [] @@ -82,7 +82,7 @@ def self.calculate(data, period: 20, constant: 0.015) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index ff30a9f..73528c0 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 20) Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -81,7 +81,7 @@ def self.calculate(data, period: 20) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 8ce4c46..03dec31 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -60,7 +60,7 @@ def self.calculate(data, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] start_price = data.first[price_key] @@ -69,7 +69,7 @@ def self.calculate(data, price_key: :value) output << { date_time: v[:date_time], value: ((v[price_key] - start_price) / start_price) } end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 573fb99..690d1a9 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -74,7 +74,7 @@ def self.calculate(data, period: 20, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -95,7 +95,7 @@ def self.calculate(data, period: 20, price_key: :value) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 3468bf3..f5011a8 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -61,7 +61,7 @@ def self.calculate(data, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_price = data.first[price_key].to_f @@ -74,7 +74,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index d3e228d..e59d6c1 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -62,7 +62,7 @@ def self.calculate(data, period: 20, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc index = period + (period / 2) - 1 midpoint_index = (period / 2) + 1 @@ -82,7 +82,7 @@ def self.calculate(data, period: 20, price_key: :value) index += 1 end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index 8666dc3..db87b6b 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -60,7 +60,7 @@ def self.calculate(data, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_price = data.first[price_key].to_f @@ -73,7 +73,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 0f0d8f7..ce6e130 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :volume) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -81,7 +81,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 5e2f233..9732fe2 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -59,7 +59,7 @@ def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_price = data.shift @@ -70,7 +70,7 @@ def self.calculate(data) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index fa52626..17cdcc5 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -87,7 +87,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(high_period: high_period, medium_period: medium_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc index = high_period + medium_period - 2 output = [] @@ -115,7 +115,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) index += 1 end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end private_class_method def self.lowest_low(prices) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 1952e33..a2157fd 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -74,7 +74,7 @@ def self.calculate(data, period: 10) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -104,7 +104,7 @@ def self.calculate(data, period: 10) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 55d0ab3..245cbd6 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -76,7 +76,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(roc4: roc4, sma4: sma4)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc index = roc4 + sma4 - 2 output = [] @@ -94,7 +94,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: index += 1 end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end private_class_method def self.calculate_rcma(data, index, price_key, roc, sma) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 63621fd..06b5194 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -80,7 +80,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(slow_period: slow_period, signal_period: signal_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc macd_values = [] output = [] @@ -124,7 +124,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 9b62cff..fe86c6b 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_typical_price = StockCalculation.typical_price(data.first) @@ -96,7 +96,7 @@ def self.calculate(data, period: 14) prev_typical_price = typical_price end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index b315cde..8938212 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -62,7 +62,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, min_data_size(ema_period: ema_period, sum_period: sum_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc double_emas = [] high_low_diffs = [] @@ -98,7 +98,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 35d15a6..438ac98 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -59,7 +59,7 @@ def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc nvi_cumulative = 1_000.00 output = [] @@ -79,7 +79,7 @@ def self.calculate(data) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index e84eb81..833e7a0 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -59,7 +59,7 @@ def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc current_obv = 0 output = [] @@ -81,7 +81,7 @@ def self.calculate(data) prior_close = close end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 6606a30..5dac9b7 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 10) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc current_obv = 0 obvs = [] @@ -87,7 +87,7 @@ def self.calculate(data, period: 10) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index ac4f1e9..cc554f4 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -62,7 +62,7 @@ def self.calculate(data, period: 14, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_price = data.shift[price_key] @@ -110,7 +110,7 @@ def self.calculate(data, period: 14, price_key: :value) prev_price = v[price_key] end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index bae9c5d..5e39994 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -62,7 +62,7 @@ def self.calculate(data, period: 30, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -75,7 +75,7 @@ def self.calculate(data, period: 30, price_key: :value) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index c4bada3..e697d86 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -74,7 +74,7 @@ def self.calculate(data, period: 14, signal_period: 3) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period, signal_period: signal_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc high_low_values = [] output = [] @@ -109,7 +109,7 @@ def self.calculate(data, period: 14, signal_period: 3) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 37faaf6..d4a20a7 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -62,7 +62,7 @@ def self.calculate(data, period: 15, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc ema1 = [] ema2 = [] @@ -104,7 +104,7 @@ def self.calculate(data, period: 15, price_key: :value) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 62d3ceb..ae56267 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -64,7 +64,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(low_period: low_period, high_period: high_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc high_emas = [] high_multiplier = (2.0 / (high_period + 1.0)) @@ -100,7 +100,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) prev_price = current_price end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end private_class_method def self.process_ema(current_value, data, multiplier, period, store) diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index b1081dc..e8f337c 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -70,7 +70,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(long_period: long_period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -100,7 +100,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh prior_close = v[:close] end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end private_class_method def self.calculate_average(period, data) diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 5a78e14..99ad6e4 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -72,7 +72,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -104,7 +104,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index be04896..d00e6e2 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -59,7 +59,7 @@ def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] prev_price = data.shift @@ -72,7 +72,7 @@ def self.calculate(data) prev_pvt = pvt end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 6c92a07..fa7d1df 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 14) Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) - data = data.sort_by_hash_date_time_asc + data = data.sort_by_date_time_asc output = [] period_values = [] @@ -80,7 +80,7 @@ def self.calculate(data, period: 14) end end - output.sort_by_hash_date_time_desc + output.sort_by_date_time_desc end end From 636cf418657d3d7773ceedc8478b688341856d4a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 16:34:32 -0500 Subject: [PATCH 30/84] Update spec for returning IndicatorValue --- .../technical_analysis/indicators/adi_spec.rb | 129 +++++++++--------- .../indicators/adtv_spec.rb | 87 ++++++------ 2 files changed, 109 insertions(+), 107 deletions(-) diff --git a/spec/technical_analysis/indicators/adi_spec.rb b/spec/technical_analysis/indicators/adi_spec.rb index ab710a2..c2d5e66 100644 --- a/spec/technical_analysis/indicators/adi_spec.rb +++ b/spec/technical_analysis/indicators/adi_spec.rb @@ -10,74 +10,75 @@ input_data = SpecHelper.get_test_data(:volume, :high, :low, :close) output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-112451134.66006838}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-135060226.53761944}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-149339794.90125585}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-170386118.17770624}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-220800308.5532927}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-139000081.24146464}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-160289759.42328274}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-155977335.67328295}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-149563792.60023466}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-191621153.9435182}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-249091249.23371798}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-215519041.4917826}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-144651314.99705797}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-109189734.6005822}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-82088668.90680213}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-84453563.11062376}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-59826989.44514345}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-23482456.813564237}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21169236.217537448}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>12348220.058324995}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>27031122.187761355}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-25774650.00158758}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>13345403.439446371}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28184142.065140743}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>7310177.429459017}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30619198.70995107}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-28229849.61904212}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-16831219.815120786}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-57716487.89688186}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-87657844.24649628}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-126035061.64521725}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-104408223.70305927}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-77157217.68155372}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-42863658.35269459}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13921718.702957403}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-31201198.431607798}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-67251111.0548819}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-19025685.861899547}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>14980297.36136794}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>59576412.70790268}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>53370009.30364728}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>52544543.51729703}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>20488006.51898352}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>8638028.433174696}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>2052056.5039138943}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>47686098.74235708}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-2596414.5729579534}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-9048353.606900878}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-22322304.45292461}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-17952613.497042313}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-16320985.571510637}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-25537009.286413625}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>9915241.57013943}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-24060850.441556394}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-17555977.138388995}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-16955140.819851194}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-13591269.009762233}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-16341921.130974408}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-37374123.7894299}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-8288954.710482582}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-37713866.134323865}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-16199273.599504825}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>22411774.711174767} + {:date_time=>"2019-01-09T00:00:00.000Z", :adi=>-112451134.66006838}, + {:date_time=>"2019-01-08T00:00:00.000Z", :adi=>-135060226.53761944}, + {:date_time=>"2019-01-07T00:00:00.000Z", :adi=>-149339794.90125585}, + {:date_time=>"2019-01-04T00:00:00.000Z", :adi=>-170386118.17770624}, + {:date_time=>"2019-01-03T00:00:00.000Z", :adi=>-220800308.5532927}, + {:date_time=>"2019-01-02T00:00:00.000Z", :adi=>-139000081.24146464}, + {:date_time=>"2018-12-31T00:00:00.000Z", :adi=>-160289759.42328274}, + {:date_time=>"2018-12-28T00:00:00.000Z", :adi=>-155977335.67328295}, + {:date_time=>"2018-12-27T00:00:00.000Z", :adi=>-149563792.60023466}, + {:date_time=>"2018-12-26T00:00:00.000Z", :adi=>-191621153.9435182}, + {:date_time=>"2018-12-24T00:00:00.000Z", :adi=>-249091249.23371798}, + {:date_time=>"2018-12-21T00:00:00.000Z", :adi=>-215519041.4917826}, + {:date_time=>"2018-12-20T00:00:00.000Z", :adi=>-144651314.99705797}, + {:date_time=>"2018-12-19T00:00:00.000Z", :adi=>-109189734.6005822}, + {:date_time=>"2018-12-18T00:00:00.000Z", :adi=>-82088668.90680213}, + {:date_time=>"2018-12-17T00:00:00.000Z", :adi=>-84453563.11062376}, + {:date_time=>"2018-12-14T00:00:00.000Z", :adi=>-59826989.44514345}, + {:date_time=>"2018-12-13T00:00:00.000Z", :adi=>-23482456.813564237}, + {:date_time=>"2018-12-12T00:00:00.000Z", :adi=>-21169236.217537448}, + {:date_time=>"2018-12-11T00:00:00.000Z", :adi=>12348220.058324995}, + {:date_time=>"2018-12-10T00:00:00.000Z", :adi=>27031122.187761355}, + {:date_time=>"2018-12-07T00:00:00.000Z", :adi=>-25774650.00158758}, + {:date_time=>"2018-12-06T00:00:00.000Z", :adi=>13345403.439446371}, + {:date_time=>"2018-12-04T00:00:00.000Z", :adi=>-28184142.065140743}, + {:date_time=>"2018-12-03T00:00:00.000Z", :adi=>7310177.429459017}, + {:date_time=>"2018-11-30T00:00:00.000Z", :adi=>-30619198.70995107}, + {:date_time=>"2018-11-29T00:00:00.000Z", :adi=>-28229849.61904212}, + {:date_time=>"2018-11-28T00:00:00.000Z", :adi=>-16831219.815120786}, + {:date_time=>"2018-11-27T00:00:00.000Z", :adi=>-57716487.89688186}, + {:date_time=>"2018-11-26T00:00:00.000Z", :adi=>-87657844.24649628}, + {:date_time=>"2018-11-23T00:00:00.000Z", :adi=>-126035061.64521725}, + {:date_time=>"2018-11-21T00:00:00.000Z", :adi=>-104408223.70305927}, + {:date_time=>"2018-11-20T00:00:00.000Z", :adi=>-77157217.68155372}, + {:date_time=>"2018-11-19T00:00:00.000Z", :adi=>-42863658.35269459}, + {:date_time=>"2018-11-16T00:00:00.000Z", :adi=>-13921718.702957403}, + {:date_time=>"2018-11-15T00:00:00.000Z", :adi=>-31201198.431607798}, + {:date_time=>"2018-11-14T00:00:00.000Z", :adi=>-67251111.0548819}, + {:date_time=>"2018-11-13T00:00:00.000Z", :adi=>-19025685.861899547}, + {:date_time=>"2018-11-12T00:00:00.000Z", :adi=>14980297.36136794}, + {:date_time=>"2018-11-09T00:00:00.000Z", :adi=>59576412.70790268}, + {:date_time=>"2018-11-08T00:00:00.000Z", :adi=>53370009.30364728}, + {:date_time=>"2018-11-07T00:00:00.000Z", :adi=>52544543.51729703}, + {:date_time=>"2018-11-06T00:00:00.000Z", :adi=>20488006.51898352}, + {:date_time=>"2018-11-05T00:00:00.000Z", :adi=>8638028.433174696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :adi=>2052056.5039138943}, + {:date_time=>"2018-11-01T00:00:00.000Z", :adi=>47686098.74235708}, + {:date_time=>"2018-10-31T00:00:00.000Z", :adi=>-2596414.5729579534}, + {:date_time=>"2018-10-30T00:00:00.000Z", :adi=>-9048353.606900878}, + {:date_time=>"2018-10-29T00:00:00.000Z", :adi=>-22322304.45292461}, + {:date_time=>"2018-10-26T00:00:00.000Z", :adi=>-17952613.497042313}, + {:date_time=>"2018-10-25T00:00:00.000Z", :adi=>-16320985.571510637}, + {:date_time=>"2018-10-24T00:00:00.000Z", :adi=>-25537009.286413625}, + {:date_time=>"2018-10-23T00:00:00.000Z", :adi=>9915241.57013943}, + {:date_time=>"2018-10-22T00:00:00.000Z", :adi=>-24060850.441556394}, + {:date_time=>"2018-10-19T00:00:00.000Z", :adi=>-17555977.138388995}, + {:date_time=>"2018-10-18T00:00:00.000Z", :adi=>-16955140.819851194}, + {:date_time=>"2018-10-17T00:00:00.000Z", :adi=>-13591269.009762233}, + {:date_time=>"2018-10-16T00:00:00.000Z", :adi=>-16341921.130974408}, + {:date_time=>"2018-10-15T00:00:00.000Z", :adi=>-37374123.7894299}, + {:date_time=>"2018-10-12T00:00:00.000Z", :adi=>-8288954.710482582}, + {:date_time=>"2018-10-11T00:00:00.000Z", :adi=>-37713866.134323865}, + {:date_time=>"2018-10-10T00:00:00.000Z", :adi=>-16199273.599504825}, + {:date_time=>"2018-10-09T00:00:00.000Z", :adi=>22411774.711174767} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it 'Returns the symbol' do diff --git a/spec/technical_analysis/indicators/adtv_spec.rb b/spec/technical_analysis/indicators/adtv_spec.rb index e34e018..5f447cd 100644 --- a/spec/technical_analysis/indicators/adtv_spec.rb +++ b/spec/technical_analysis/indicators/adtv_spec.rb @@ -9,53 +9,54 @@ describe 'Average Daily Trading Volume' do it 'Calculates ADTV (22 day)' do output = indicator.calculate(input_data, period: 22, volume_key: :volume) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>49513676.36363637}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>49407791.81818182}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>49431352.72727273}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>48793455.45454545}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>47975301.36363637}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>45721516.81818182}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46189911.36363637}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>46492490.90909091}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>46625296.36363637}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>45353256.36363637}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>44124274.09090909}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>45511067.27272727}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>43062381.81818182}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>41780250.0}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>41719976.81818182}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>42937879.09090909}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43095846.81818182}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>43567240.90909091}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43683765.90909091}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>43220792.72727273}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>42644592.72727273}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>41281670.90909091}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>42390465.90909091}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>44587813.63636363}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>45124760.0}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>45010174.09090909}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>44876704.54545455}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>45067164.09090909}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>45123980.0}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>44572670.90909091}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>44360389.09090909}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>45044807.27272727}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>44938230.0}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>43356214.09090909}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>42936325.90909091}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>42322760.0}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>41528709.54545455}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>40152941.81818182}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>39824262.72727273}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>39911139.54545455}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>40218699.09090909}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40280851.81818182} + {:date_time=>"2019-01-09T00:00:00.000Z", :adtv=>49513676.36363637}, + {:date_time=>"2019-01-08T00:00:00.000Z", :adtv=>49407791.81818182}, + {:date_time=>"2019-01-07T00:00:00.000Z", :adtv=>49431352.72727273}, + {:date_time=>"2019-01-04T00:00:00.000Z", :adtv=>48793455.45454545}, + {:date_time=>"2019-01-03T00:00:00.000Z", :adtv=>47975301.36363637}, + {:date_time=>"2019-01-02T00:00:00.000Z", :adtv=>45721516.81818182}, + {:date_time=>"2018-12-31T00:00:00.000Z", :adtv=>46189911.36363637}, + {:date_time=>"2018-12-28T00:00:00.000Z", :adtv=>46492490.90909091}, + {:date_time=>"2018-12-27T00:00:00.000Z", :adtv=>46625296.36363637}, + {:date_time=>"2018-12-26T00:00:00.000Z", :adtv=>45353256.36363637}, + {:date_time=>"2018-12-24T00:00:00.000Z", :adtv=>44124274.09090909}, + {:date_time=>"2018-12-21T00:00:00.000Z", :adtv=>45511067.27272727}, + {:date_time=>"2018-12-20T00:00:00.000Z", :adtv=>43062381.81818182}, + {:date_time=>"2018-12-19T00:00:00.000Z", :adtv=>41780250.0}, + {:date_time=>"2018-12-18T00:00:00.000Z", :adtv=>41719976.81818182}, + {:date_time=>"2018-12-17T00:00:00.000Z", :adtv=>42937879.09090909}, + {:date_time=>"2018-12-14T00:00:00.000Z", :adtv=>43095846.81818182}, + {:date_time=>"2018-12-13T00:00:00.000Z", :adtv=>43567240.90909091}, + {:date_time=>"2018-12-12T00:00:00.000Z", :adtv=>43683765.90909091}, + {:date_time=>"2018-12-11T00:00:00.000Z", :adtv=>43220792.72727273}, + {:date_time=>"2018-12-10T00:00:00.000Z", :adtv=>42644592.72727273}, + {:date_time=>"2018-12-07T00:00:00.000Z", :adtv=>41281670.90909091}, + {:date_time=>"2018-12-06T00:00:00.000Z", :adtv=>42390465.90909091}, + {:date_time=>"2018-12-04T00:00:00.000Z", :adtv=>44587813.63636363}, + {:date_time=>"2018-12-03T00:00:00.000Z", :adtv=>45124760.0}, + {:date_time=>"2018-11-30T00:00:00.000Z", :adtv=>45010174.09090909}, + {:date_time=>"2018-11-29T00:00:00.000Z", :adtv=>44876704.54545455}, + {:date_time=>"2018-11-28T00:00:00.000Z", :adtv=>45067164.09090909}, + {:date_time=>"2018-11-27T00:00:00.000Z", :adtv=>45123980.0}, + {:date_time=>"2018-11-26T00:00:00.000Z", :adtv=>44572670.90909091}, + {:date_time=>"2018-11-23T00:00:00.000Z", :adtv=>44360389.09090909}, + {:date_time=>"2018-11-21T00:00:00.000Z", :adtv=>45044807.27272727}, + {:date_time=>"2018-11-20T00:00:00.000Z", :adtv=>44938230.0}, + {:date_time=>"2018-11-19T00:00:00.000Z", :adtv=>43356214.09090909}, + {:date_time=>"2018-11-16T00:00:00.000Z", :adtv=>42936325.90909091}, + {:date_time=>"2018-11-15T00:00:00.000Z", :adtv=>42322760.0}, + {:date_time=>"2018-11-14T00:00:00.000Z", :adtv=>41528709.54545455}, + {:date_time=>"2018-11-13T00:00:00.000Z", :adtv=>40152941.81818182}, + {:date_time=>"2018-11-12T00:00:00.000Z", :adtv=>39824262.72727273}, + {:date_time=>"2018-11-09T00:00:00.000Z", :adtv=>39911139.54545455}, + {:date_time=>"2018-11-08T00:00:00.000Z", :adtv=>40218699.09090909}, + {:date_time=>"2018-11-07T00:00:00.000Z", :adtv=>40280851.81818182} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From e618600625043993f4497220572ed7fc81208d2e Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 16:50:36 -0500 Subject: [PATCH 31/84] Update Adx with AdxValue --- lib/technical_analysis/indicators/adx.rb | 64 ++++++++-------- .../technical_analysis/indicators/adx_spec.rb | 75 ++++++++++--------- 2 files changed, 71 insertions(+), 68 deletions(-) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index e162cea..533ec80 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Average Direcitonal Index class Adx < Indicator # Returns the symbol of the technical indicator @@ -47,28 +48,7 @@ def self.min_data_size(period: 14) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the ADX # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :adx => 46.70506819299097, - # :di_neg => 33.86727845364526, - # :di_pos => 18.75156069669946 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :adx => 48.08801057392937, - # :di_neg => 35.92768510004254, - # :di_pos => 16.527665969119678 - # } - # }, - # ] + # @return [Array] An array of AdxValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -107,14 +87,7 @@ def self.calculate(data, period: 14) adx = ((prev_adx * 13) + dx) / period.to_f end - output << { - date_time: v[:date_time], - value: { - adx: adx, - di_pos: di_pos, - di_neg: di_neg - } - } + output << AdxValue.new(date_time: v[:date_time], adx: adx, di_pos: di_pos, di_neg: di_neg) prev_adx = adx dx_values.shift @@ -143,7 +116,7 @@ def self.calculate(data, period: 14) [dm_pos, dm_neg] end - + private_class_method def self.smooth_periodic_values(period, periodic_values, smoothed_values) if smoothed_values.empty? tr_period = periodic_values.map { |pv| pv[:tr] }.sum @@ -161,5 +134,34 @@ def self.calculate(data, period: 14) [tr_period, dm_pos_period, dm_neg_period] end + # The value class to be returned by calculations + class AdxValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the adx calculation value + attr_accessor :adx + + # @return [Float] the positive directional indicator calculation value + attr_accessor :di_pos + + # @return [Float] the negative directional indicator calculation value + attr_accessor :di_neg + + def initialize(date_time: nil, adx: nil, di_pos: nil, di_neg: nil) + @date_time = date_time + @adx = adx + @di_pos = di_pos + @di_neg = di_neg + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, adx: @adx, di_pos: @di_pos, di_neg: @di_neg } + end + + end + end end diff --git a/spec/technical_analysis/indicators/adx_spec.rb b/spec/technical_analysis/indicators/adx_spec.rb index 67047ae..4dcab41 100644 --- a/spec/technical_analysis/indicators/adx_spec.rb +++ b/spec/technical_analysis/indicators/adx_spec.rb @@ -9,47 +9,48 @@ describe 'Average Directional Index' do it 'Calculates ADX (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:adx=>48.08801057392937, :di_neg=>35.92768510004254, :di_pos=>16.527665969119678}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443}} + {:date_time=>"2019-01-09T00:00:00.000Z", :adx=>46.70506819299097, :di_neg=>33.86727845364526, :di_pos=>18.75156069669946}, + {:date_time=>"2019-01-08T00:00:00.000Z", :adx=>48.08801057392937, :di_neg=>35.92768510004254, :di_pos=>16.527665969119678}, + {:date_time=>"2019-01-07T00:00:00.000Z", :adx=>48.9421751918944, :di_neg=>37.61461933766297, :di_pos=>13.69466932452777}, + {:date_time=>"2019-01-04T00:00:00.000Z", :adx=>49.12087007192141, :di_neg=>38.89182421063156, :di_pos=>13.835071344467728}, + {:date_time=>"2019-01-03T00:00:00.000Z", :adx=>49.24387794011257, :di_neg=>41.7490776508834, :di_pos=>11.582515799387362}, + {:date_time=>"2019-01-02T00:00:00.000Z", :adx=>48.68078018528377, :di_neg=>34.52657095260412, :di_pos=>13.967710052992748}, + {:date_time=>"2018-12-31T00:00:00.000Z", :adx=>49.16434766454135, :di_neg=>33.6937638052496, :di_pos=>14.788354298902822}, + {:date_time=>"2018-12-28T00:00:00.000Z", :adx=>49.94663571159158, :di_neg=>34.986926565583936, :di_pos=>14.325926339774329}, + {:date_time=>"2018-12-27T00:00:00.000Z", :adx=>50.56577696054131, :di_neg=>36.643305871956294, :di_pos=>12.91725635739372}, + {:date_time=>"2018-12-26T00:00:00.000Z", :adx=>50.77292582473832, :di_neg=>39.7700574645743, :di_pos=>14.019478193733173}, + {:date_time=>"2018-12-24T00:00:00.000Z", :adx=>50.9960092169505, :di_neg=>45.054464306949185, :di_pos=>8.701290502977864}, + {:date_time=>"2018-12-21T00:00:00.000Z", :adx=>49.71673521777664, :di_neg=>44.050625611685426, :di_pos=>9.239278206391834}, + {:date_time=>"2018-12-20T00:00:00.000Z", :adx=>48.516140209610576, :di_neg=>41.59440646182574, :di_pos=>10.25145625667257}, + {:date_time=>"2018-12-19T00:00:00.000Z", :adx=>47.59783553446671, :di_neg=>40.351684937107876, :di_pos=>11.15761353425932}, + {:date_time=>"2018-12-18T00:00:00.000Z", :adx=>46.89941641847421, :di_neg=>37.76941014220763, :di_pos=>12.407839995022263}, + {:date_time=>"2018-12-17T00:00:00.000Z", :adx=>46.61906677289316, :di_neg=>39.53590570860133, :di_pos=>12.988161325358192}, + {:date_time=>"2018-12-14T00:00:00.000Z", :adx=>46.31715176995973, :di_neg=>39.11005826049996, :di_pos=>13.935609588410411}, + {:date_time=>"2018-12-13T00:00:00.000Z", :adx=>46.2293890478109, :di_neg=>36.454819093692386, :di_pos=>14.957814674775397}, + {:date_time=>"2018-12-12T00:00:00.000Z", :adx=>46.56913524205153, :di_neg=>38.04051607484649, :di_pos=>14.793647188928983}, + {:date_time=>"2018-12-11T00:00:00.000Z", :adx=>46.76678475437397, :di_neg=>39.55530357861321, :di_pos=>15.225390789013932}, + {:date_time=>"2018-12-10T00:00:00.000Z", :adx=>46.94782223161259, :di_neg=>41.80590109058211, :di_pos=>14.07235093039379}, + {:date_time=>"2018-12-07T00:00:00.000Z", :adx=>46.74133929346658, :di_neg=>39.25064431094187, :di_pos=>15.206157858128352}, + {:date_time=>"2018-12-06T00:00:00.000Z", :adx=>46.94041765413575, :di_neg=>39.72706616642713, :di_pos=>16.369223356492178}, + {:date_time=>"2018-12-04T00:00:00.000Z", :adx=>47.348231515991635, :di_neg=>35.733971514512405, :di_pos=>17.589281738284058}, + {:date_time=>"2018-12-03T00:00:00.000Z", :adx=>48.37288589247055, :di_neg=>33.43673559814864, :di_pos=>19.42230137516784}, + {:date_time=>"2018-11-30T00:00:00.000Z", :adx=>50.05442754589659, :di_neg=>36.030275362364435, :di_pos=>15.306518521740204}, + {:date_time=>"2018-11-29T00:00:00.000Z", :adx=>50.79951939347192, :di_neg=>36.64084491661032, :di_pos=>15.900754457889013}, + {:date_time=>"2018-11-28T00:00:00.000Z", :adx=>51.67073961575017, :di_neg=>38.80264418160902, :di_pos=>15.0920401856127}, + {:date_time=>"2018-11-27T00:00:00.000Z", :adx=>52.261232848231245, :di_neg=>41.98206441213049, :di_pos=>8.75082128345464}, + {:date_time=>"2018-11-26T00:00:00.000Z", :adx=>51.24268374123445, :di_neg=>43.821787689533835, :di_pos=>9.134296699373357}, + {:date_time=>"2018-11-23T00:00:00.000Z", :adx=>50.14578470293022, :di_neg=>44.05855841207259, :di_pos=>9.605544411876144}, + {:date_time=>"2018-11-21T00:00:00.000Z", :adx=>49.0645966148012, :di_neg=>41.4968168736661, :di_pos=>10.08777861559222}, + {:date_time=>"2018-11-20T00:00:00.000Z", :adx=>48.15507276775653, :di_neg=>43.093658309800155, :di_pos=>10.47596701425822}, + {:date_time=>"2018-11-19T00:00:00.000Z", :adx=>47.17558554786226, :di_neg=>37.739607295468765, :di_pos=>11.632425406517202}, + {:date_time=>"2018-11-16T00:00:00.000Z", :adx=>46.73690113316023, :di_neg=>36.39042671024342, :di_pos=>12.707203247013513}, + {:date_time=>"2018-11-15T00:00:00.000Z", :adx=>46.621508959519026, :di_neg=>38.52265796697687, :di_pos=>10.26180913708443} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 984cca9b884bf7be92c95a2a163fd0e52935ae2f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 16:53:59 -0500 Subject: [PATCH 32/84] Add AoValue --- lib/technical_analysis/indicators/ao.rb | 33 +++++++--- spec/technical_analysis/indicators/ao_spec.rb | 63 ++++++++++--------- 2 files changed, 56 insertions(+), 40 deletions(-) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 96f6c78..8577e2f 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Awesome Oscillator class Ao < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(long_period: 34, **params) # @param short_period [Integer] The given period to calculate the short period SMA # @param long_period [Integer] The given period to calculate the long period SMA # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -17.518757058823525}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -17.8071908823529}, - # ] + # @return [Array] An array of AoValue instances def self.calculate(data, short_period: 5, long_period: 34) short_period = short_period.to_i long_period = long_period.to_i @@ -76,7 +70,7 @@ def self.calculate(data, short_period: 5, long_period: 34) long_period_sma = midpoint_values.average value = short_period_sma - long_period_sma - output << { date_time: v[:date_time], value: value } + output << AoValue.new(date_time: v[:date_time], ao: value) midpoint_values.shift end @@ -86,4 +80,25 @@ def self.calculate(data, short_period: 5, long_period: 34) end end + + # The value class to be returned by calculations + class AoValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the ao calculation value + attr_accessor :ao + + def initialize(date_time: nil, ao: nil) + @date_time = date_time + @ao = ao + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, ao: @ao } + end + + end end diff --git a/spec/technical_analysis/indicators/ao_spec.rb b/spec/technical_analysis/indicators/ao_spec.rb index a7fb9b1..3e077b9 100644 --- a/spec/technical_analysis/indicators/ao_spec.rb +++ b/spec/technical_analysis/indicators/ao_spec.rb @@ -9,41 +9,42 @@ describe 'Awesome Oscillator' do it 'Calculates AO (5 day short period, 34 day long period)' do output = indicator.calculate(input_data, short_period: 5, long_period: 34) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-17.518757058823525}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-17.8071908823529}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-17.41204382352936}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-16.838043823529347}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-16.804919117647017}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-16.73956617647059}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-19.633272058823536}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.924007352941203}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.97706617647063}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.471330882352987}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-21.124477941176536}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-19.609007352941205}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-18.88406617647061}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-18.17277205882357}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18.17262500000004}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18.865919117647138}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-20.12868382352943}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-20.811713235294178}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-21.92503676470585}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-21.579664411764696}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-20.365870294117656}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-19.51995852941178}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-19.071752647058815}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-19.392987941176415}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-21.886519117646998}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-25.05331323529407}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-27.130989705882314}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-28.547813235294086}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-29.739166176470576}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-28.26261029411762} + {:date_time=>"2019-01-09T00:00:00.000Z", :ao=>-17.518757058823525}, + {:date_time=>"2019-01-08T00:00:00.000Z", :ao=>-17.8071908823529}, + {:date_time=>"2019-01-07T00:00:00.000Z", :ao=>-17.41204382352936}, + {:date_time=>"2019-01-04T00:00:00.000Z", :ao=>-16.838043823529347}, + {:date_time=>"2019-01-03T00:00:00.000Z", :ao=>-16.804919117647017}, + {:date_time=>"2019-01-02T00:00:00.000Z", :ao=>-16.73956617647059}, + {:date_time=>"2018-12-31T00:00:00.000Z", :ao=>-19.633272058823536}, + {:date_time=>"2018-12-28T00:00:00.000Z", :ao=>-21.924007352941203}, + {:date_time=>"2018-12-27T00:00:00.000Z", :ao=>-22.97706617647063}, + {:date_time=>"2018-12-26T00:00:00.000Z", :ao=>-22.471330882352987}, + {:date_time=>"2018-12-24T00:00:00.000Z", :ao=>-21.124477941176536}, + {:date_time=>"2018-12-21T00:00:00.000Z", :ao=>-19.609007352941205}, + {:date_time=>"2018-12-20T00:00:00.000Z", :ao=>-18.88406617647061}, + {:date_time=>"2018-12-19T00:00:00.000Z", :ao=>-18.17277205882357}, + {:date_time=>"2018-12-18T00:00:00.000Z", :ao=>-18.17262500000004}, + {:date_time=>"2018-12-17T00:00:00.000Z", :ao=>-18.865919117647138}, + {:date_time=>"2018-12-14T00:00:00.000Z", :ao=>-20.12868382352943}, + {:date_time=>"2018-12-13T00:00:00.000Z", :ao=>-20.811713235294178}, + {:date_time=>"2018-12-12T00:00:00.000Z", :ao=>-21.92503676470585}, + {:date_time=>"2018-12-11T00:00:00.000Z", :ao=>-21.579664411764696}, + {:date_time=>"2018-12-10T00:00:00.000Z", :ao=>-20.365870294117656}, + {:date_time=>"2018-12-07T00:00:00.000Z", :ao=>-19.51995852941178}, + {:date_time=>"2018-12-06T00:00:00.000Z", :ao=>-19.071752647058815}, + {:date_time=>"2018-12-04T00:00:00.000Z", :ao=>-19.392987941176415}, + {:date_time=>"2018-12-03T00:00:00.000Z", :ao=>-21.886519117646998}, + {:date_time=>"2018-11-30T00:00:00.000Z", :ao=>-25.05331323529407}, + {:date_time=>"2018-11-29T00:00:00.000Z", :ao=>-27.130989705882314}, + {:date_time=>"2018-11-28T00:00:00.000Z", :ao=>-28.547813235294086}, + {:date_time=>"2018-11-27T00:00:00.000Z", :ao=>-29.739166176470576}, + {:date_time=>"2018-11-26T00:00:00.000Z", :ao=>-28.26261029411762} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 0f8cda6d3e92b7a5effa46e84bbfc39d0165ae81 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 17:06:37 -0500 Subject: [PATCH 33/84] Fix atr --- lib/technical_analysis/indicators/atr.rb | 35 ++++-- .../technical_analysis/indicators/atr_spec.rb | 101 +++++++++--------- 2 files changed, 76 insertions(+), 60 deletions(-) diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index b692708..39b3d2d 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Average True Range class Atr < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(period: 14) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the ATR # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 6.103013600253306}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 6.195553107965099}, - # ] + # @return [Array] An array of AtrValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -75,10 +69,10 @@ def self.calculate(data, period: 14) if output.empty? atr = period_values.average else - atr = (output.last[:value] * (period - 1.0) + tr) / period.to_f + atr = (output.last.atr * (period - 1.0) + tr) / period.to_f end - output << { date_time: v[:date_time], value: atr } + output << AtrValue.new(date_time: v[:date_time], atr: atr) period_values.shift end @@ -90,4 +84,25 @@ def self.calculate(data, period: 14) end end + + # The value class to be returned by calculations + class AtrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the atr calculation value + attr_accessor :atr + + def initialize(date_time: nil, atr: nil) + @date_time = date_time + @atr = atr + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, atr: @atr } + end + + end end diff --git a/spec/technical_analysis/indicators/atr_spec.rb b/spec/technical_analysis/indicators/atr_spec.rb index 34fab31..39c304e 100644 --- a/spec/technical_analysis/indicators/atr_spec.rb +++ b/spec/technical_analysis/indicators/atr_spec.rb @@ -9,60 +9,61 @@ describe 'Average True Range' do it 'Calculates ATR (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>6.103013600253306}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>6.195553107965099}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>6.3729033470393395}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>6.637742066042365}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>6.6591145326610075}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>5.946738727481086}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>6.048795552671939}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>6.273318287492855}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>6.450496617299998}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>6.400534818630767}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>6.084422112371596}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>6.170916121015564}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>5.989448130324453}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>5.926328755734025}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>5.739123275405874}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>5.904440450437095}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>5.926320485086102}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>5.946037445477343}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>6.1365018643602145}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>6.355463546234078}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>6.475883819021315}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>6.4540287281768025}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>6.456646322651943}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>6.471003732086706}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>6.311080942247224}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>6.307317937804704}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>6.538650086866604}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>6.649315478164034}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>6.618493591868961}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>6.828377714320418}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>6.9928683077296805}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>7.1707812544781175}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>7.43622596636105}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>7.212089502234975}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>7.109942540868436}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>7.233053505550622}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>7.391749929054517}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>7.302653769751019}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>7.423634828962634}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>7.173145200421298}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>7.244925600453705}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>7.542996800488605}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>7.63938116975696}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>7.98625664435365}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>7.884430232380852}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>7.199386404102457}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>7.326262281341107}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>7.339820918367347}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>7.449807142857144} + {:date_time=>"2019-01-09T00:00:00.000Z", :atr=>6.103013600253306}, + {:date_time=>"2019-01-08T00:00:00.000Z", :atr=>6.195553107965099}, + {:date_time=>"2019-01-07T00:00:00.000Z", :atr=>6.3729033470393395}, + {:date_time=>"2019-01-04T00:00:00.000Z", :atr=>6.637742066042365}, + {:date_time=>"2019-01-03T00:00:00.000Z", :atr=>6.6591145326610075}, + {:date_time=>"2019-01-02T00:00:00.000Z", :atr=>5.946738727481086}, + {:date_time=>"2018-12-31T00:00:00.000Z", :atr=>6.048795552671939}, + {:date_time=>"2018-12-28T00:00:00.000Z", :atr=>6.273318287492855}, + {:date_time=>"2018-12-27T00:00:00.000Z", :atr=>6.450496617299998}, + {:date_time=>"2018-12-26T00:00:00.000Z", :atr=>6.400534818630767}, + {:date_time=>"2018-12-24T00:00:00.000Z", :atr=>6.084422112371596}, + {:date_time=>"2018-12-21T00:00:00.000Z", :atr=>6.170916121015564}, + {:date_time=>"2018-12-20T00:00:00.000Z", :atr=>5.989448130324453}, + {:date_time=>"2018-12-19T00:00:00.000Z", :atr=>5.926328755734025}, + {:date_time=>"2018-12-18T00:00:00.000Z", :atr=>5.739123275405874}, + {:date_time=>"2018-12-17T00:00:00.000Z", :atr=>5.904440450437095}, + {:date_time=>"2018-12-14T00:00:00.000Z", :atr=>5.926320485086102}, + {:date_time=>"2018-12-13T00:00:00.000Z", :atr=>5.946037445477343}, + {:date_time=>"2018-12-12T00:00:00.000Z", :atr=>6.1365018643602145}, + {:date_time=>"2018-12-11T00:00:00.000Z", :atr=>6.355463546234078}, + {:date_time=>"2018-12-10T00:00:00.000Z", :atr=>6.475883819021315}, + {:date_time=>"2018-12-07T00:00:00.000Z", :atr=>6.4540287281768025}, + {:date_time=>"2018-12-06T00:00:00.000Z", :atr=>6.456646322651943}, + {:date_time=>"2018-12-04T00:00:00.000Z", :atr=>6.471003732086706}, + {:date_time=>"2018-12-03T00:00:00.000Z", :atr=>6.311080942247224}, + {:date_time=>"2018-11-30T00:00:00.000Z", :atr=>6.307317937804704}, + {:date_time=>"2018-11-29T00:00:00.000Z", :atr=>6.538650086866604}, + {:date_time=>"2018-11-28T00:00:00.000Z", :atr=>6.649315478164034}, + {:date_time=>"2018-11-27T00:00:00.000Z", :atr=>6.618493591868961}, + {:date_time=>"2018-11-26T00:00:00.000Z", :atr=>6.828377714320418}, + {:date_time=>"2018-11-23T00:00:00.000Z", :atr=>6.9928683077296805}, + {:date_time=>"2018-11-21T00:00:00.000Z", :atr=>7.1707812544781175}, + {:date_time=>"2018-11-20T00:00:00.000Z", :atr=>7.43622596636105}, + {:date_time=>"2018-11-19T00:00:00.000Z", :atr=>7.212089502234975}, + {:date_time=>"2018-11-16T00:00:00.000Z", :atr=>7.109942540868436}, + {:date_time=>"2018-11-15T00:00:00.000Z", :atr=>7.233053505550622}, + {:date_time=>"2018-11-14T00:00:00.000Z", :atr=>7.391749929054517}, + {:date_time=>"2018-11-13T00:00:00.000Z", :atr=>7.302653769751019}, + {:date_time=>"2018-11-12T00:00:00.000Z", :atr=>7.423634828962634}, + {:date_time=>"2018-11-09T00:00:00.000Z", :atr=>7.173145200421298}, + {:date_time=>"2018-11-08T00:00:00.000Z", :atr=>7.244925600453705}, + {:date_time=>"2018-11-07T00:00:00.000Z", :atr=>7.542996800488605}, + {:date_time=>"2018-11-06T00:00:00.000Z", :atr=>7.63938116975696}, + {:date_time=>"2018-11-05T00:00:00.000Z", :atr=>7.98625664435365}, + {:date_time=>"2018-11-02T00:00:00.000Z", :atr=>7.884430232380852}, + {:date_time=>"2018-11-01T00:00:00.000Z", :atr=>7.199386404102457}, + {:date_time=>"2018-10-31T00:00:00.000Z", :atr=>7.326262281341107}, + {:date_time=>"2018-10-30T00:00:00.000Z", :atr=>7.339820918367347}, + {:date_time=>"2018-10-29T00:00:00.000Z", :atr=>7.449807142857144} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 9af83bc8980a9db80c75d93656e3e09dff40f865 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 17:06:49 -0500 Subject: [PATCH 34/84] Add BbValue --- lib/technical_analysis/indicators/bb.rb | 73 +++++++++------ spec/technical_analysis/indicators/bb_spec.rb | 91 ++++++++++--------- 2 files changed, 89 insertions(+), 75 deletions(-) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index ed3e376..fff6db2 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Bollinger Bands class Bb < Indicator # Returns the symbol of the technical indicator @@ -46,31 +47,11 @@ def self.min_data_size(period: 20, **params) # # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the BB - # @param standard_deviations [Float] The given standard deviations to calculate the upper and lower bands of the BB + # @param standard_deviations [Float] The given standard deviations to calculate the upper and + # lower bands of the BB # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :lower_band => 141.02036711220762, - # :middle_band => 157.35499999999996, - # :upper_band => 173.6896328877923 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value=> { - # :lower_band => 141.07714470666247, - # :middle_band => 158.1695, - # :upper_band => 175.26185529333753 - # } - # }, - # ] + # @return [Array] An array of BbValue instances def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) period = period.to_i standard_deviations = standard_deviations.to_f @@ -92,14 +73,12 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) ub = mb + standard_deviations * sd lb = mb - standard_deviations * sd - output << { + output << BbValue.new( date_time: v[:date_time], - value: { - middle_band: mb, - upper_band: ub, - lower_band: lb - } - } + lower_band: lb, + middle_band: mb, + upper_band: ub + ) period_values.shift end @@ -109,4 +88,38 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) end end + + # The value class to be returned by calculations + class BbValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the lower_band calculation value + attr_accessor :lower_band + + # @return [Float] the middle_band calculation value + attr_accessor :middle_band + + # @return [Float] the upper_band calculation value + attr_accessor :upper_band + + def initialize(date_time: nil, lower_band: nil, middle_band: nil, upper_band: nil) + @date_time = date_time + @lower_band = lower_band + @middle_band = middle_band + @upper_band = upper_band + end + + # @return [Hash] the attributes as a hash + def to_hash + { + date_time: @date_time, + lower_band: @lower_band, + middle_band: @middle_band, + upper_band: @upper_band + } + end + + end end diff --git a/spec/technical_analysis/indicators/bb_spec.rb b/spec/technical_analysis/indicators/bb_spec.rb index 4847522..af59d3d 100644 --- a/spec/technical_analysis/indicators/bb_spec.rb +++ b/spec/technical_analysis/indicators/bb_spec.rb @@ -9,55 +9,56 @@ describe 'Bollinger Bands' do it 'Calculates BB (20, 2)' do output = indicator.calculate(input_data, period: 20, standard_deviations: 2, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>141.07714470666247, :middle_band=>158.1695, :upper_band=>175.26185529333753}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863}} + {:date_time=>"2019-01-09T00:00:00.000Z", :lower_band=>141.02036711220762, :middle_band=>157.35499999999996, :upper_band=>173.6896328877923}, + {:date_time=>"2019-01-08T00:00:00.000Z", :lower_band=>141.07714470666247, :middle_band=>158.1695, :upper_band=>175.26185529333753}, + {:date_time=>"2019-01-07T00:00:00.000Z", :lower_band=>141.74551015326722, :middle_band=>159.05649999999997, :upper_band=>176.36748984673272}, + {:date_time=>"2019-01-04T00:00:00.000Z", :lower_band=>142.5717393007821, :middle_band=>160.39600000000002, :upper_band=>178.22026069921793}, + {:date_time=>"2019-01-03T00:00:00.000Z", :lower_band=>143.53956406332316, :middle_band=>161.8175, :upper_band=>180.09543593667684}, + {:date_time=>"2019-01-02T00:00:00.000Z", :lower_band=>145.3682834538487, :middle_band=>163.949, :upper_band=>182.52971654615132}, + {:date_time=>"2018-12-31T00:00:00.000Z", :lower_band=>145.53555575730587, :middle_band=>164.98199999999997, :upper_band=>184.42844424269407}, + {:date_time=>"2018-12-28T00:00:00.000Z", :lower_band=>145.90334076589886, :middle_band=>166.0725, :upper_band=>186.24165923410112}, + {:date_time=>"2018-12-27T00:00:00.000Z", :lower_band=>146.65592111904317, :middle_band=>167.308, :upper_band=>187.96007888095681}, + {:date_time=>"2018-12-26T00:00:00.000Z", :lower_band=>148.0390209273478, :middle_band=>168.2125, :upper_band=>188.38597907265222}, + {:date_time=>"2018-12-24T00:00:00.000Z", :lower_band=>149.41938426834125, :middle_band=>169.08499999999998, :upper_band=>188.7506157316587}, + {:date_time=>"2018-12-21T00:00:00.000Z", :lower_band=>153.6905118237551, :middle_band=>170.35799999999998, :upper_band=>187.02548817624486}, + {:date_time=>"2018-12-20T00:00:00.000Z", :lower_band=>157.58081627897096, :middle_band=>171.6605, :upper_band=>185.74018372102907}, + {:date_time=>"2018-12-19T00:00:00.000Z", :lower_band=>160.2737711222648, :middle_band=>172.66799999999998, :upper_band=>185.06222887773515}, + {:date_time=>"2018-12-18T00:00:00.000Z", :lower_band=>161.48722339827833, :middle_band=>173.91649999999998, :upper_band=>186.34577660172164}, + {:date_time=>"2018-12-17T00:00:00.000Z", :lower_band=>160.6411151779543, :middle_band=>175.28949999999995, :upper_band=>189.9378848220456}, + {:date_time=>"2018-12-14T00:00:00.000Z", :lower_band=>161.3586392867227, :middle_band=>176.66299999999998, :upper_band=>191.96736071327726}, + {:date_time=>"2018-12-13T00:00:00.000Z", :lower_band=>162.73753871102127, :middle_band=>177.72899999999998, :upper_band=>192.7204612889787}, + {:date_time=>"2018-12-12T00:00:00.000Z", :lower_band=>162.83769519003326, :middle_band=>178.79299999999998, :upper_band=>194.7483048099667}, + {:date_time=>"2018-12-11T00:00:00.000Z", :lower_band=>163.37450359253498, :middle_band=>180.04649999999998, :upper_band=>196.71849640746498}, + {:date_time=>"2018-12-10T00:00:00.000Z", :lower_band=>162.797082234342, :middle_band=>181.8385, :upper_band=>200.879917765658}, + {:date_time=>"2018-12-07T00:00:00.000Z", :lower_band=>162.2270311355715, :middle_band=>183.783, :upper_band=>205.33896886442847}, + {:date_time=>"2018-12-06T00:00:00.000Z", :lower_band=>162.58630667652835, :middle_band=>185.856, :upper_band=>209.12569332347164}, + {:date_time=>"2018-12-04T00:00:00.000Z", :lower_band=>163.34919566513827, :middle_band=>187.30850000000004, :upper_band=>211.2678043348618}, + {:date_time=>"2018-12-03T00:00:00.000Z", :lower_band=>164.3311203741903, :middle_band=>188.55350000000004, :upper_band=>212.77587962580978}, + {:date_time=>"2018-11-30T00:00:00.000Z", :lower_band=>164.11704019466114, :middle_band=>189.68650000000005, :upper_band=>215.25595980533896}, + {:date_time=>"2018-11-29T00:00:00.000Z", :lower_band=>163.04822623308377, :middle_band=>191.8685, :upper_band=>220.68877376691626}, + {:date_time=>"2018-11-28T00:00:00.000Z", :lower_band=>163.2435966888823, :middle_band=>193.83400000000003, :upper_band=>224.42440331111777}, + {:date_time=>"2018-11-27T00:00:00.000Z", :lower_band=>164.31484291109825, :middle_band=>195.45200000000006, :upper_band=>226.58915708890186}, + {:date_time=>"2018-11-26T00:00:00.000Z", :lower_band=>167.03813268520582, :middle_band=>197.35200000000003, :upper_band=>227.66586731479424}, + {:date_time=>"2018-11-23T00:00:00.000Z", :lower_band=>169.9836589081704, :middle_band=>199.436, :upper_band=>228.8883410918296}, + {:date_time=>"2018-11-21T00:00:00.000Z", :lower_band=>173.9574856242928, :middle_band=>201.81150000000002, :upper_band=>229.66551437570726}, + {:date_time=>"2018-11-20T00:00:00.000Z", :lower_band=>177.92765761752017, :middle_band=>203.72700000000003, :upper_band=>229.5263423824799}, + {:date_time=>"2018-11-19T00:00:00.000Z", :lower_band=>182.16105406114465, :middle_band=>206.0145, :upper_band=>229.86794593885534}, + {:date_time=>"2018-11-16T00:00:00.000Z", :lower_band=>185.04223870650642, :middle_band=>207.75399999999996, :upper_band=>230.4657612934935}, + {:date_time=>"2018-11-15T00:00:00.000Z", :lower_band=>186.80906188255153, :middle_band=>209.04299999999998, :upper_band=>231.27693811744842}, + {:date_time=>"2018-11-14T00:00:00.000Z", :lower_band=>189.47053333403466, :middle_band=>210.27349999999996, :upper_band=>231.07646666596526}, + {:date_time=>"2018-11-13T00:00:00.000Z", :lower_band=>193.84357681067348, :middle_band=>211.993, :upper_band=>230.1424231893265}, + {:date_time=>"2018-11-12T00:00:00.000Z", :lower_band=>197.38090736241395, :middle_band=>213.48899999999998, :upper_band=>229.597092637586}, + {:date_time=>"2018-11-09T00:00:00.000Z", :lower_band=>201.29218743765117, :middle_band=>214.6485, :upper_band=>228.00481256234886}, + {:date_time=>"2018-11-08T00:00:00.000Z", :lower_band=>202.68427348053234, :middle_band=>215.5305, :upper_band=>228.37672651946764}, + {:date_time=>"2018-11-07T00:00:00.000Z", :lower_band=>203.4002295525166, :middle_band=>215.82850000000002, :upper_band=>228.25677044748343}, + {:date_time=>"2018-11-06T00:00:00.000Z", :lower_band=>204.03232701561498, :middle_band=>216.14900000000003, :upper_band=>228.26567298438508}, + {:date_time=>"2018-11-05T00:00:00.000Z", :lower_band=>205.76564218562143, :middle_band=>217.30400000000003, :upper_band=>228.84235781437863} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From dd77168dfca7c200919960ff596d0d6714d67485 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 17:24:20 -0500 Subject: [PATCH 35/84] Add CciValue, CmfValue, CrValue, DcValue, DlrValue --- lib/technical_analysis/indicators/cci.rb | 33 +++-- lib/technical_analysis/indicators/cmf.rb | 34 +++-- lib/technical_analysis/indicators/cr.rb | 36 +++-- lib/technical_analysis/indicators/dc.rb | 57 ++++---- lib/technical_analysis/indicators/dlr.rb | 33 +++-- .../technical_analysis/indicators/cci_spec.rb | 91 ++++++------ .../technical_analysis/indicators/cmf_spec.rb | 91 ++++++------ spec/technical_analysis/indicators/cr_spec.rb | 129 +++++++++--------- spec/technical_analysis/indicators/dc_spec.rb | 91 ++++++------ .../technical_analysis/indicators/dlr_spec.rb | 129 +++++++++--------- 10 files changed, 399 insertions(+), 325 deletions(-) diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 782ce06..677f726 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -49,14 +49,7 @@ def self.min_data_size(period: 20, **params) # @param constant [Float] The given constant to ensure that approximately 70 to 80 percent of # CCI values would fall between −100 and +100 # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -48.14847062019609}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -72.7408611895969}, - # ] + # @return [Array] An array of CciValue instances def self.calculate(data, period: 20, constant: 0.015) period = period.to_i constant = constant.to_f @@ -77,7 +70,8 @@ def self.calculate(data, period: 20, constant: 0.015) mean_deviation = typical_prices.map { |tp| (tp - period_sma).abs }.mean cci = (typical_price - period_sma) / (constant * mean_deviation) - output << { date_time: v[:date_time], value: cci } + output << CciValue.new(date_time: v[:date_time], cci: cci) + typical_prices.shift end end @@ -86,4 +80,25 @@ def self.calculate(data, period: 20, constant: 0.015) end end + + # The value class to be returned by calculations + class CciValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the cci calculation value + attr_accessor :cci + + def initialize(date_time: nil, cci: nil) + @date_time = date_time + @cci = cci + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, cci: @cci } + end + + end end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 73528c0..6ee707b 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Chaikin Money Flow class Cmf < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(period: 20) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the CMF # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.14148236474171028}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.10900349402409147}, - # ] + # @return [Array] An array of CmfValue instances def self.calculate(data, period: 20) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) @@ -76,7 +70,8 @@ def self.calculate(data, period: 20) mf_volume_sum = period_values.map { |pv| pv[:mf_volume] }.sum cmf = mf_volume_sum / volume_sum - output << { date_time: v[:date_time], value: cmf } + output << CmfValue.new(date_time: v[:date_time], cmf: cmf) + period_values.shift end end @@ -85,4 +80,25 @@ def self.calculate(data, period: 20) end end + + # The value class to be returned by calculations + class CmfValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the cmf calculation value + attr_accessor :cmf + + def initialize(date_time: nil, cmf: nil) + @date_time = date_time + @cmf = cmf + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, cmf: @cmf } + end + + end end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 03dec31..7e32fdc 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Cumulative Return class Cr < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.3242385507118614}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.33552254595142594}, - # ] + # @return [Array] An array of CrValue instances def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) @@ -66,11 +60,35 @@ def self.calculate(data, price_key: :value) start_price = data.first[price_key] data.each do |v| - output << { date_time: v[:date_time], value: ((v[price_key] - start_price) / start_price) } + output << CrValue.new( + date_time: v[:date_time], + cr: ((v[price_key] - start_price) / start_price) + ) end output.sort_by_date_time_desc end end + + # The value class to be returned by calculations + class CrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the cr calculation value + attr_accessor :cr + + def initialize(date_time: nil, cr: nil) + @date_time = date_time + @cr = cr + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, cr: @cr } + end + + end end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 690d1a9..1f865e3 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Donchian Channel class Dc < Indicator # Returns the symbol of the technical indicator @@ -48,26 +49,7 @@ def self.min_data_size(period: 20, **params) # @param period [Integer] The given period to calculate the DC # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :lower_bound => 142.19, - # :upper_bound => 170.95 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :lower_bound => 142.19, - # :upper_bound => 170.95 - # } - # }, - # ] + # @return [Array] An array of DcValue instances def self.calculate(data, period: 20, price_key: :value) period = period.to_i price_key = price_key.to_sym @@ -83,13 +65,11 @@ def self.calculate(data, period: 20, price_key: :value) period_values << v[price_key] if period_values.size == period - output << { + output << DcValue.new( date_time: v[:date_time], - value: { - upper_bound: period_values.max, - lower_bound: period_values.min - } - } + upper_bound: period_values.max, + lower_bound: period_values.min + ) period_values.shift end @@ -99,4 +79,29 @@ def self.calculate(data, period: 20, price_key: :value) end end + + # The value class to be returned by calculations + class DcValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the upper_bound calculation value + attr_accessor :upper_bound + + # @return [Float] the lower_bound calculation value + attr_accessor :lower_bound + + def initialize(date_time: nil, upper_bound: nil, lower_bound: ninl) + @date_time = date_time + @upper_bound = upper_bound + @lower_bound = lower_bound + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, upper_bound: @upper_bound, lower_bound: @lower_bound } + end + + end end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index f5011a8..fd2a5e2 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Daily Log Return class Dlr < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(**params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 0.01683917971506794}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 0.01888364670315034}, - # ] + # @return [Array] An array of DlrValue instances def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) @@ -69,7 +63,7 @@ def self.calculate(data, price_key: :value) data.each do |v| current_price = v[:close].to_f - output << { date_time: v[:date_time], value: Math.log(current_price / prev_price) } + output << DlrValue.new(date_time: v[:date_time], dlr: Math.log(current_price / prev_price)) prev_price = current_price end @@ -78,4 +72,25 @@ def self.calculate(data, price_key: :value) end end + + # The value class to be returned by calculations + class DlrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the dlr calculation value + attr_accessor :dlr + + def initialize(date_time: nil, dlr: nil) + @date_time = date_time + @dlr = dlr + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, dlr: @dlr } + end + + end end diff --git a/spec/technical_analysis/indicators/cci_spec.rb b/spec/technical_analysis/indicators/cci_spec.rb index 196574d..c8365a6 100644 --- a/spec/technical_analysis/indicators/cci_spec.rb +++ b/spec/technical_analysis/indicators/cci_spec.rb @@ -9,55 +9,56 @@ describe 'Commodity Channel Index' do it 'Calculates CCI (20 day)' do output = indicator.calculate(input_data, period: 20, constant: 0.015) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-48.14847062019609}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-72.7408611895969}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-103.45330536502108}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-119.01911861945885}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-162.69069349674928}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-62.42850721332871}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-62.94237272962061}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-82.72457326337747}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-109.82143904961333}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-130.89740843118958}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-205.86763488625635}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-204.3001270602558}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-175.655233047097}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-145.86611021295013}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-108.36683776743406}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-123.22931274779911}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-114.79798652194032}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-77.37092752385674}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-93.5619842292165}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-105.1287325078536}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-118.83020945347108}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-102.13101656480995}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-87.66403875835518}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-60.69535791887537}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-32.43699792850786}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-68.8774176049022}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-67.42425893465922}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-79.16162769465076}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-117.06521007698558}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-130.57777507098388}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-145.81148745067057}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-143.70909871161282}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-166.092016017792}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-129.79321417259732}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-109.8703962546515}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-144.29736082195598}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-176.53554346437872}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-170.11758119513328}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-179.88996064655686}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-121.3842764199079}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-88.26723659204252}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-107.40409620543349}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-198.71238766942466}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-281.5255251804358} + {:date_time=>"2019-01-09T00:00:00.000Z", :cci=>-48.14847062019609}, + {:date_time=>"2019-01-08T00:00:00.000Z", :cci=>-72.7408611895969}, + {:date_time=>"2019-01-07T00:00:00.000Z", :cci=>-103.45330536502108}, + {:date_time=>"2019-01-04T00:00:00.000Z", :cci=>-119.01911861945885}, + {:date_time=>"2019-01-03T00:00:00.000Z", :cci=>-162.69069349674928}, + {:date_time=>"2019-01-02T00:00:00.000Z", :cci=>-62.42850721332871}, + {:date_time=>"2018-12-31T00:00:00.000Z", :cci=>-62.94237272962061}, + {:date_time=>"2018-12-28T00:00:00.000Z", :cci=>-82.72457326337747}, + {:date_time=>"2018-12-27T00:00:00.000Z", :cci=>-109.82143904961333}, + {:date_time=>"2018-12-26T00:00:00.000Z", :cci=>-130.89740843118958}, + {:date_time=>"2018-12-24T00:00:00.000Z", :cci=>-205.86763488625635}, + {:date_time=>"2018-12-21T00:00:00.000Z", :cci=>-204.3001270602558}, + {:date_time=>"2018-12-20T00:00:00.000Z", :cci=>-175.655233047097}, + {:date_time=>"2018-12-19T00:00:00.000Z", :cci=>-145.86611021295013}, + {:date_time=>"2018-12-18T00:00:00.000Z", :cci=>-108.36683776743406}, + {:date_time=>"2018-12-17T00:00:00.000Z", :cci=>-123.22931274779911}, + {:date_time=>"2018-12-14T00:00:00.000Z", :cci=>-114.79798652194032}, + {:date_time=>"2018-12-13T00:00:00.000Z", :cci=>-77.37092752385674}, + {:date_time=>"2018-12-12T00:00:00.000Z", :cci=>-93.5619842292165}, + {:date_time=>"2018-12-11T00:00:00.000Z", :cci=>-105.1287325078536}, + {:date_time=>"2018-12-10T00:00:00.000Z", :cci=>-118.83020945347108}, + {:date_time=>"2018-12-07T00:00:00.000Z", :cci=>-102.13101656480995}, + {:date_time=>"2018-12-06T00:00:00.000Z", :cci=>-87.66403875835518}, + {:date_time=>"2018-12-04T00:00:00.000Z", :cci=>-60.69535791887537}, + {:date_time=>"2018-12-03T00:00:00.000Z", :cci=>-32.43699792850786}, + {:date_time=>"2018-11-30T00:00:00.000Z", :cci=>-68.8774176049022}, + {:date_time=>"2018-11-29T00:00:00.000Z", :cci=>-67.42425893465922}, + {:date_time=>"2018-11-28T00:00:00.000Z", :cci=>-79.16162769465076}, + {:date_time=>"2018-11-27T00:00:00.000Z", :cci=>-117.06521007698558}, + {:date_time=>"2018-11-26T00:00:00.000Z", :cci=>-130.57777507098388}, + {:date_time=>"2018-11-23T00:00:00.000Z", :cci=>-145.81148745067057}, + {:date_time=>"2018-11-21T00:00:00.000Z", :cci=>-143.70909871161282}, + {:date_time=>"2018-11-20T00:00:00.000Z", :cci=>-166.092016017792}, + {:date_time=>"2018-11-19T00:00:00.000Z", :cci=>-129.79321417259732}, + {:date_time=>"2018-11-16T00:00:00.000Z", :cci=>-109.8703962546515}, + {:date_time=>"2018-11-15T00:00:00.000Z", :cci=>-144.29736082195598}, + {:date_time=>"2018-11-14T00:00:00.000Z", :cci=>-176.53554346437872}, + {:date_time=>"2018-11-13T00:00:00.000Z", :cci=>-170.11758119513328}, + {:date_time=>"2018-11-12T00:00:00.000Z", :cci=>-179.88996064655686}, + {:date_time=>"2018-11-09T00:00:00.000Z", :cci=>-121.3842764199079}, + {:date_time=>"2018-11-08T00:00:00.000Z", :cci=>-88.26723659204252}, + {:date_time=>"2018-11-07T00:00:00.000Z", :cci=>-107.40409620543349}, + {:date_time=>"2018-11-06T00:00:00.000Z", :cci=>-198.71238766942466}, + {:date_time=>"2018-11-05T00:00:00.000Z", :cci=>-281.5255251804358} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/cmf_spec.rb b/spec/technical_analysis/indicators/cmf_spec.rb index 302e455..949c27a 100644 --- a/spec/technical_analysis/indicators/cmf_spec.rb +++ b/spec/technical_analysis/indicators/cmf_spec.rb @@ -9,55 +9,56 @@ describe 'Chaikin Money Flow' do it 'Calculates CMF (20 day)' do output = indicator.calculate(input_data, period: 20) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.14148236474171028}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.10900349402409147}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.16209459049078995}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.14338098793972473}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.23384083275693518}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.1171779554311941}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.1421967277504723}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.14870217725852253}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.09771633750350824}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.11185040161958644}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.13433878933016613}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.12311876857928804}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.08053545285645361}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.07883316711924936}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.08160027269601758}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0635610565928198}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>0.008829457014340984}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.005177700749048257}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.041279122544240626}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.05299093511730075}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.02994416009907359}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.09289096149170357}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.008556645577315109}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044697234566322144}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.006195178249247199}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.08707816577338795}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.02808273355873217}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.008559410227273146}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.039334642581608396}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.07707518115228632}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.12097582444999905}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0864519745264971}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.09451983283878523}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.02107439975862456}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.004132959703610273}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.016262278292090777}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.06224056395025631}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.00325588286845078}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>0.06492697386482489}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>0.08638139363431603}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>0.11517576782439708}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.0839939173853672}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.002328367522189358}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>0.010519910116535688} + {:date_time=>"2019-01-09T00:00:00.000Z", :cmf=>-0.14148236474171028}, + {:date_time=>"2019-01-08T00:00:00.000Z", :cmf=>-0.10900349402409147}, + {:date_time=>"2019-01-07T00:00:00.000Z", :cmf=>-0.16209459049078995}, + {:date_time=>"2019-01-04T00:00:00.000Z", :cmf=>-0.14338098793972473}, + {:date_time=>"2019-01-03T00:00:00.000Z", :cmf=>-0.23384083275693518}, + {:date_time=>"2019-01-02T00:00:00.000Z", :cmf=>-0.1171779554311941}, + {:date_time=>"2018-12-31T00:00:00.000Z", :cmf=>-0.1421967277504723}, + {:date_time=>"2018-12-28T00:00:00.000Z", :cmf=>-0.14870217725852253}, + {:date_time=>"2018-12-27T00:00:00.000Z", :cmf=>-0.09771633750350824}, + {:date_time=>"2018-12-26T00:00:00.000Z", :cmf=>-0.11185040161958644}, + {:date_time=>"2018-12-24T00:00:00.000Z", :cmf=>-0.13433878933016613}, + {:date_time=>"2018-12-21T00:00:00.000Z", :cmf=>-0.12311876857928804}, + {:date_time=>"2018-12-20T00:00:00.000Z", :cmf=>-0.08053545285645361}, + {:date_time=>"2018-12-19T00:00:00.000Z", :cmf=>-0.07883316711924936}, + {:date_time=>"2018-12-18T00:00:00.000Z", :cmf=>-0.08160027269601758}, + {:date_time=>"2018-12-17T00:00:00.000Z", :cmf=>-0.0635610565928198}, + {:date_time=>"2018-12-14T00:00:00.000Z", :cmf=>0.008829457014340984}, + {:date_time=>"2018-12-13T00:00:00.000Z", :cmf=>-0.005177700749048257}, + {:date_time=>"2018-12-12T00:00:00.000Z", :cmf=>-0.041279122544240626}, + {:date_time=>"2018-12-11T00:00:00.000Z", :cmf=>-0.05299093511730075}, + {:date_time=>"2018-12-10T00:00:00.000Z", :cmf=>-0.02994416009907359}, + {:date_time=>"2018-12-07T00:00:00.000Z", :cmf=>-0.09289096149170357}, + {:date_time=>"2018-12-06T00:00:00.000Z", :cmf=>-0.008556645577315109}, + {:date_time=>"2018-12-04T00:00:00.000Z", :cmf=>-0.044697234566322144}, + {:date_time=>"2018-12-03T00:00:00.000Z", :cmf=>0.006195178249247199}, + {:date_time=>"2018-11-30T00:00:00.000Z", :cmf=>-0.08707816577338795}, + {:date_time=>"2018-11-29T00:00:00.000Z", :cmf=>-0.02808273355873217}, + {:date_time=>"2018-11-28T00:00:00.000Z", :cmf=>-0.008559410227273146}, + {:date_time=>"2018-11-27T00:00:00.000Z", :cmf=>-0.039334642581608396}, + {:date_time=>"2018-11-26T00:00:00.000Z", :cmf=>-0.07707518115228632}, + {:date_time=>"2018-11-23T00:00:00.000Z", :cmf=>-0.12097582444999905}, + {:date_time=>"2018-11-21T00:00:00.000Z", :cmf=>-0.0864519745264971}, + {:date_time=>"2018-11-20T00:00:00.000Z", :cmf=>-0.09451983283878523}, + {:date_time=>"2018-11-19T00:00:00.000Z", :cmf=>-0.02107439975862456}, + {:date_time=>"2018-11-16T00:00:00.000Z", :cmf=>0.004132959703610273}, + {:date_time=>"2018-11-15T00:00:00.000Z", :cmf=>-0.016262278292090777}, + {:date_time=>"2018-11-14T00:00:00.000Z", :cmf=>-0.06224056395025631}, + {:date_time=>"2018-11-13T00:00:00.000Z", :cmf=>-0.00325588286845078}, + {:date_time=>"2018-11-12T00:00:00.000Z", :cmf=>0.06492697386482489}, + {:date_time=>"2018-11-09T00:00:00.000Z", :cmf=>0.08638139363431603}, + {:date_time=>"2018-11-08T00:00:00.000Z", :cmf=>0.11517576782439708}, + {:date_time=>"2018-11-07T00:00:00.000Z", :cmf=>0.0839939173853672}, + {:date_time=>"2018-11-06T00:00:00.000Z", :cmf=>-0.002328367522189358}, + {:date_time=>"2018-11-05T00:00:00.000Z", :cmf=>0.010519910116535688} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/cr_spec.rb b/spec/technical_analysis/indicators/cr_spec.rb index db8fc46..7e926f1 100644 --- a/spec/technical_analysis/indicators/cr_spec.rb +++ b/spec/technical_analysis/indicators/cr_spec.rb @@ -9,74 +9,75 @@ describe 'Cumulative Return' do it 'Calculates CR' do output = indicator.calculate(input_data, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.3242385507118614}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.33552254595142594}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.34795257195750867}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.34649799444615864}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.3732534050337198}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.30391854365936444}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.30471194957464626}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.3113677436417332}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.3117203684929695}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.3072244016397056}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.35280116366200903}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.3356107021642351}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.3087230572574602}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.29082734605721344}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.2679948869396571}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.277383523603826}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.2705954952175255}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.2464847710142373}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.2546392206990788}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.2567108917000926}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-0.2524353153788514}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.25732798518975625}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.22986732489972234}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.2211839379380262}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-0.185348437431128}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.2128531758275664}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.20857759950632518}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-0.20245074271609295}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.23198307400714063}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-0.2303081059637678}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.24057830475602773}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.22078723498038524}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.21990567285229431}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.18076431436505483}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-0.14695640675276592}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-0.15630096531053028}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.17662097236302726}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.15268656058535732}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.14413540794287485}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.09873495834618948}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.08101555957156079}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-0.07458015603649674}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-0.10182042579450784}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.11142945299069952}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0854674483184203}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-0.020496319478115244}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-0.035306563230043594}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-0.05981399039097277}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.06448626966985496}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.046590558469608113}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-0.031163221228016014}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.05192400934455856}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-0.018248336051483294}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-0.027416582183629384}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-0.03332304844183895}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.04782474544893549}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.025036364437783783}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-0.02080486622294706}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.041918279190725924}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-0.02098117864856522}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.054745008154449756}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.04632608983118081}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} + {:date_time=>"2019-01-09T00:00:00.000Z", :cr=>-0.3242385507118614}, + {:date_time=>"2019-01-08T00:00:00.000Z", :cr=>-0.33552254595142594}, + {:date_time=>"2019-01-07T00:00:00.000Z", :cr=>-0.34795257195750867}, + {:date_time=>"2019-01-04T00:00:00.000Z", :cr=>-0.34649799444615864}, + {:date_time=>"2019-01-03T00:00:00.000Z", :cr=>-0.3732534050337198}, + {:date_time=>"2019-01-02T00:00:00.000Z", :cr=>-0.30391854365936444}, + {:date_time=>"2018-12-31T00:00:00.000Z", :cr=>-0.30471194957464626}, + {:date_time=>"2018-12-28T00:00:00.000Z", :cr=>-0.3113677436417332}, + {:date_time=>"2018-12-27T00:00:00.000Z", :cr=>-0.3117203684929695}, + {:date_time=>"2018-12-26T00:00:00.000Z", :cr=>-0.3072244016397056}, + {:date_time=>"2018-12-24T00:00:00.000Z", :cr=>-0.35280116366200903}, + {:date_time=>"2018-12-21T00:00:00.000Z", :cr=>-0.3356107021642351}, + {:date_time=>"2018-12-20T00:00:00.000Z", :cr=>-0.3087230572574602}, + {:date_time=>"2018-12-19T00:00:00.000Z", :cr=>-0.29082734605721344}, + {:date_time=>"2018-12-18T00:00:00.000Z", :cr=>-0.2679948869396571}, + {:date_time=>"2018-12-17T00:00:00.000Z", :cr=>-0.277383523603826}, + {:date_time=>"2018-12-14T00:00:00.000Z", :cr=>-0.2705954952175255}, + {:date_time=>"2018-12-13T00:00:00.000Z", :cr=>-0.2464847710142373}, + {:date_time=>"2018-12-12T00:00:00.000Z", :cr=>-0.2546392206990788}, + {:date_time=>"2018-12-11T00:00:00.000Z", :cr=>-0.2567108917000926}, + {:date_time=>"2018-12-10T00:00:00.000Z", :cr=>-0.2524353153788514}, + {:date_time=>"2018-12-07T00:00:00.000Z", :cr=>-0.25732798518975625}, + {:date_time=>"2018-12-06T00:00:00.000Z", :cr=>-0.22986732489972234}, + {:date_time=>"2018-12-04T00:00:00.000Z", :cr=>-0.2211839379380262}, + {:date_time=>"2018-12-03T00:00:00.000Z", :cr=>-0.185348437431128}, + {:date_time=>"2018-11-30T00:00:00.000Z", :cr=>-0.2128531758275664}, + {:date_time=>"2018-11-29T00:00:00.000Z", :cr=>-0.20857759950632518}, + {:date_time=>"2018-11-28T00:00:00.000Z", :cr=>-0.20245074271609295}, + {:date_time=>"2018-11-27T00:00:00.000Z", :cr=>-0.23198307400714063}, + {:date_time=>"2018-11-26T00:00:00.000Z", :cr=>-0.2303081059637678}, + {:date_time=>"2018-11-23T00:00:00.000Z", :cr=>-0.24057830475602773}, + {:date_time=>"2018-11-21T00:00:00.000Z", :cr=>-0.22078723498038524}, + {:date_time=>"2018-11-20T00:00:00.000Z", :cr=>-0.21990567285229431}, + {:date_time=>"2018-11-19T00:00:00.000Z", :cr=>-0.18076431436505483}, + {:date_time=>"2018-11-16T00:00:00.000Z", :cr=>-0.14695640675276592}, + {:date_time=>"2018-11-15T00:00:00.000Z", :cr=>-0.15630096531053028}, + {:date_time=>"2018-11-14T00:00:00.000Z", :cr=>-0.17662097236302726}, + {:date_time=>"2018-11-13T00:00:00.000Z", :cr=>-0.15268656058535732}, + {:date_time=>"2018-11-12T00:00:00.000Z", :cr=>-0.14413540794287485}, + {:date_time=>"2018-11-09T00:00:00.000Z", :cr=>-0.09873495834618948}, + {:date_time=>"2018-11-08T00:00:00.000Z", :cr=>-0.08101555957156079}, + {:date_time=>"2018-11-07T00:00:00.000Z", :cr=>-0.07458015603649674}, + {:date_time=>"2018-11-06T00:00:00.000Z", :cr=>-0.10182042579450784}, + {:date_time=>"2018-11-05T00:00:00.000Z", :cr=>-0.11142945299069952}, + {:date_time=>"2018-11-02T00:00:00.000Z", :cr=>-0.0854674483184203}, + {:date_time=>"2018-11-01T00:00:00.000Z", :cr=>-0.020496319478115244}, + {:date_time=>"2018-10-31T00:00:00.000Z", :cr=>-0.035306563230043594}, + {:date_time=>"2018-10-30T00:00:00.000Z", :cr=>-0.05981399039097277}, + {:date_time=>"2018-10-29T00:00:00.000Z", :cr=>-0.06448626966985496}, + {:date_time=>"2018-10-26T00:00:00.000Z", :cr=>-0.046590558469608113}, + {:date_time=>"2018-10-25T00:00:00.000Z", :cr=>-0.031163221228016014}, + {:date_time=>"2018-10-24T00:00:00.000Z", :cr=>-0.05192400934455856}, + {:date_time=>"2018-10-23T00:00:00.000Z", :cr=>-0.018248336051483294}, + {:date_time=>"2018-10-22T00:00:00.000Z", :cr=>-0.027416582183629384}, + {:date_time=>"2018-10-19T00:00:00.000Z", :cr=>-0.03332304844183895}, + {:date_time=>"2018-10-18T00:00:00.000Z", :cr=>-0.04782474544893549}, + {:date_time=>"2018-10-17T00:00:00.000Z", :cr=>-0.025036364437783783}, + {:date_time=>"2018-10-16T00:00:00.000Z", :cr=>-0.02080486622294706}, + {:date_time=>"2018-10-15T00:00:00.000Z", :cr=>-0.041918279190725924}, + {:date_time=>"2018-10-12T00:00:00.000Z", :cr=>-0.02098117864856522}, + {:date_time=>"2018-10-11T00:00:00.000Z", :cr=>-0.054745008154449756}, + {:date_time=>"2018-10-10T00:00:00.000Z", :cr=>-0.04632608983118081}, + {:date_time=>"2018-10-09T00:00:00.000Z", :cr=>0.0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/dc_spec.rb b/spec/technical_analysis/indicators/dc_spec.rb index 8ad3865..d64183e 100644 --- a/spec/technical_analysis/indicators/dc_spec.rb +++ b/spec/technical_analysis/indicators/dc_spec.rb @@ -9,55 +9,56 @@ describe 'Donchian Channel' do it 'Calculates DC (20 day)' do output = indicator.calculate(input_data, period: 20, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>170.95}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>174.72}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:lower_bound=>142.19, :upper_bound=>176.69}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:lower_bound=>146.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:lower_bound=>150.73, :upper_bound=>184.82}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:lower_bound=>156.83, :upper_bound=>184.82}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:lower_bound=>160.89, :upper_bound=>184.82}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>185.86}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:lower_bound=>163.94, :upper_bound=>193.53}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:lower_bound=>165.48, :upper_bound=>193.53}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>193.53}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>194.17}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>204.47}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:lower_bound=>168.49, :upper_bound=>208.49}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>209.95}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:lower_bound=>172.29, :upper_bound=>222.22}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:lower_bound=>176.78, :upper_bound=>222.22}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:lower_bound=>176.98, :upper_bound=>222.22}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:lower_bound=>185.86, :upper_bound=>222.73}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:lower_bound=>186.8, :upper_bound=>222.73}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:lower_bound=>192.23, :upper_bound=>222.73}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:lower_bound=>194.17, :upper_bound=>222.73}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>222.73}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:lower_bound=>201.59, :upper_bound=>226.87}} + {:date_time=>"2019-01-09T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95}, + {:date_time=>"2019-01-08T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95}, + {:date_time=>"2019-01-07T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>170.95}, + {:date_time=>"2019-01-04T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>174.72}, + {:date_time=>"2019-01-03T00:00:00.000Z", :lower_bound=>142.19, :upper_bound=>176.69}, + {:date_time=>"2019-01-02T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-31T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-28T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-27T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-26T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-24T00:00:00.000Z", :lower_bound=>146.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-21T00:00:00.000Z", :lower_bound=>150.73, :upper_bound=>184.82}, + {:date_time=>"2018-12-20T00:00:00.000Z", :lower_bound=>156.83, :upper_bound=>184.82}, + {:date_time=>"2018-12-19T00:00:00.000Z", :lower_bound=>160.89, :upper_bound=>184.82}, + {:date_time=>"2018-12-18T00:00:00.000Z", :lower_bound=>163.94, :upper_bound=>185.86}, + {:date_time=>"2018-12-17T00:00:00.000Z", :lower_bound=>163.94, :upper_bound=>193.53}, + {:date_time=>"2018-12-14T00:00:00.000Z", :lower_bound=>165.48, :upper_bound=>193.53}, + {:date_time=>"2018-12-13T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>193.53}, + {:date_time=>"2018-12-12T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>193.53}, + {:date_time=>"2018-12-11T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>194.17}, + {:date_time=>"2018-12-10T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>204.47}, + {:date_time=>"2018-12-07T00:00:00.000Z", :lower_bound=>168.49, :upper_bound=>208.49}, + {:date_time=>"2018-12-06T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95}, + {:date_time=>"2018-12-04T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95}, + {:date_time=>"2018-12-03T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95}, + {:date_time=>"2018-11-30T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>209.95}, + {:date_time=>"2018-11-29T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22}, + {:date_time=>"2018-11-28T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22}, + {:date_time=>"2018-11-27T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22}, + {:date_time=>"2018-11-26T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22}, + {:date_time=>"2018-11-23T00:00:00.000Z", :lower_bound=>172.29, :upper_bound=>222.22}, + {:date_time=>"2018-11-21T00:00:00.000Z", :lower_bound=>176.78, :upper_bound=>222.22}, + {:date_time=>"2018-11-20T00:00:00.000Z", :lower_bound=>176.98, :upper_bound=>222.22}, + {:date_time=>"2018-11-19T00:00:00.000Z", :lower_bound=>185.86, :upper_bound=>222.73}, + {:date_time=>"2018-11-16T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73}, + {:date_time=>"2018-11-15T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73}, + {:date_time=>"2018-11-14T00:00:00.000Z", :lower_bound=>186.8, :upper_bound=>222.73}, + {:date_time=>"2018-11-13T00:00:00.000Z", :lower_bound=>192.23, :upper_bound=>222.73}, + {:date_time=>"2018-11-12T00:00:00.000Z", :lower_bound=>194.17, :upper_bound=>222.73}, + {:date_time=>"2018-11-09T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73}, + {:date_time=>"2018-11-08T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73}, + {:date_time=>"2018-11-07T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73}, + {:date_time=>"2018-11-06T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>222.73}, + {:date_time=>"2018-11-05T00:00:00.000Z", :lower_bound=>201.59, :upper_bound=>226.87} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/dlr_spec.rb b/spec/technical_analysis/indicators/dlr_spec.rb index 0a9a384..2f45204 100644 --- a/spec/technical_analysis/indicators/dlr_spec.rb +++ b/spec/technical_analysis/indicators/dlr_spec.rb @@ -9,74 +9,75 @@ describe 'Daily Log Return' do it 'Calculates Daily Log Return' do output = indicator.calculate(input_data, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01683917971506794}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.01888364670315034}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022283003244291597}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.04180329782029066}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.10492438427688831}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011404677153263752}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009618827546033224}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.0005121966947240164}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006510938359150324}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.06805256711339175}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.026214701847591528}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.039672259323895565}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.02555848551661011}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.03168848455571821}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.012908878993777004}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.0093498343683261}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.032520774492099586}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010880860180775654}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.002783290222441408}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.00573575767570937}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.00656632250750863}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03630829170624626}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011212092072018474}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.044985593831335616}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.034345698370823956}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005417040583021469}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.007711763925503673}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.037731825412945244}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.002178525198011193}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013433080838346925}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.02572691808848715}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011307102064021337}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.04895697028998929}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.04043883708306672}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011014814954241668}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.024379198463276127}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.028654045970026604}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.010041492241593453}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.051687201448600596}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.01946981300300202}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006978328672237313}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.029877500317357083}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010755975020512992}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028799017690867113}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.0686329326726632}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015235626165565584}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.025732630512992103}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004981915647820579}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018948623129528868}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.0160517090105079}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021661496781179467}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.03490373037505153}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009382539847836957}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006091481696142526}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.01511525802908552}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023651064679340767}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.0043307687122485835}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.02179786426382509}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021617789532325248}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.03509614368752819}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.008867076040336814}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.047433479205543055}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} + {:date_time=>"2019-01-09T00:00:00.000Z", :dlr=>0.01683917971506794}, + {:date_time=>"2019-01-08T00:00:00.000Z", :dlr=>0.01888364670315034}, + {:date_time=>"2019-01-07T00:00:00.000Z", :dlr=>-0.0022283003244291597}, + {:date_time=>"2019-01-04T00:00:00.000Z", :dlr=>0.04180329782029066}, + {:date_time=>"2019-01-03T00:00:00.000Z", :dlr=>-0.10492438427688831}, + {:date_time=>"2019-01-02T00:00:00.000Z", :dlr=>0.0011404677153263752}, + {:date_time=>"2018-12-31T00:00:00.000Z", :dlr=>0.009618827546033224}, + {:date_time=>"2018-12-28T00:00:00.000Z", :dlr=>0.0005121966947240164}, + {:date_time=>"2018-12-27T00:00:00.000Z", :dlr=>-0.006510938359150324}, + {:date_time=>"2018-12-26T00:00:00.000Z", :dlr=>0.06805256711339175}, + {:date_time=>"2018-12-24T00:00:00.000Z", :dlr=>-0.026214701847591528}, + {:date_time=>"2018-12-21T00:00:00.000Z", :dlr=>-0.039672259323895565}, + {:date_time=>"2018-12-20T00:00:00.000Z", :dlr=>-0.02555848551661011}, + {:date_time=>"2018-12-19T00:00:00.000Z", :dlr=>-0.03168848455571821}, + {:date_time=>"2018-12-18T00:00:00.000Z", :dlr=>0.012908878993777004}, + {:date_time=>"2018-12-17T00:00:00.000Z", :dlr=>-0.0093498343683261}, + {:date_time=>"2018-12-14T00:00:00.000Z", :dlr=>-0.032520774492099586}, + {:date_time=>"2018-12-13T00:00:00.000Z", :dlr=>0.010880860180775654}, + {:date_time=>"2018-12-12T00:00:00.000Z", :dlr=>0.002783290222441408}, + {:date_time=>"2018-12-11T00:00:00.000Z", :dlr=>-0.00573575767570937}, + {:date_time=>"2018-12-10T00:00:00.000Z", :dlr=>0.00656632250750863}, + {:date_time=>"2018-12-07T00:00:00.000Z", :dlr=>-0.03630829170624626}, + {:date_time=>"2018-12-06T00:00:00.000Z", :dlr=>-0.011212092072018474}, + {:date_time=>"2018-12-04T00:00:00.000Z", :dlr=>-0.044985593831335616}, + {:date_time=>"2018-12-03T00:00:00.000Z", :dlr=>0.034345698370823956}, + {:date_time=>"2018-11-30T00:00:00.000Z", :dlr=>-0.005417040583021469}, + {:date_time=>"2018-11-29T00:00:00.000Z", :dlr=>-0.007711763925503673}, + {:date_time=>"2018-11-28T00:00:00.000Z", :dlr=>0.037731825412945244}, + {:date_time=>"2018-11-27T00:00:00.000Z", :dlr=>-0.002178525198011193}, + {:date_time=>"2018-11-26T00:00:00.000Z", :dlr=>0.013433080838346925}, + {:date_time=>"2018-11-23T00:00:00.000Z", :dlr=>-0.02572691808848715}, + {:date_time=>"2018-11-21T00:00:00.000Z", :dlr=>-0.0011307102064021337}, + {:date_time=>"2018-11-20T00:00:00.000Z", :dlr=>-0.04895697028998929}, + {:date_time=>"2018-11-19T00:00:00.000Z", :dlr=>-0.04043883708306672}, + {:date_time=>"2018-11-16T00:00:00.000Z", :dlr=>0.011014814954241668}, + {:date_time=>"2018-11-15T00:00:00.000Z", :dlr=>0.024379198463276127}, + {:date_time=>"2018-11-14T00:00:00.000Z", :dlr=>-0.028654045970026604}, + {:date_time=>"2018-11-13T00:00:00.000Z", :dlr=>-0.010041492241593453}, + {:date_time=>"2018-11-12T00:00:00.000Z", :dlr=>-0.051687201448600596}, + {:date_time=>"2018-11-09T00:00:00.000Z", :dlr=>-0.01946981300300202}, + {:date_time=>"2018-11-08T00:00:00.000Z", :dlr=>-0.006978328672237313}, + {:date_time=>"2018-11-07T00:00:00.000Z", :dlr=>0.029877500317357083}, + {:date_time=>"2018-11-06T00:00:00.000Z", :dlr=>0.010755975020512992}, + {:date_time=>"2018-11-05T00:00:00.000Z", :dlr=>-0.028799017690867113}, + {:date_time=>"2018-11-02T00:00:00.000Z", :dlr=>-0.0686329326726632}, + {:date_time=>"2018-11-01T00:00:00.000Z", :dlr=>0.015235626165565584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :dlr=>0.025732630512992103}, + {:date_time=>"2018-10-30T00:00:00.000Z", :dlr=>0.004981915647820579}, + {:date_time=>"2018-10-29T00:00:00.000Z", :dlr=>-0.018948623129528868}, + {:date_time=>"2018-10-26T00:00:00.000Z", :dlr=>-0.0160517090105079}, + {:date_time=>"2018-10-25T00:00:00.000Z", :dlr=>0.021661496781179467}, + {:date_time=>"2018-10-24T00:00:00.000Z", :dlr=>-0.03490373037505153}, + {:date_time=>"2018-10-23T00:00:00.000Z", :dlr=>0.009382539847836957}, + {:date_time=>"2018-10-22T00:00:00.000Z", :dlr=>0.006091481696142526}, + {:date_time=>"2018-10-19T00:00:00.000Z", :dlr=>0.01511525802908552}, + {:date_time=>"2018-10-18T00:00:00.000Z", :dlr=>-0.023651064679340767}, + {:date_time=>"2018-10-17T00:00:00.000Z", :dlr=>-0.0043307687122485835}, + {:date_time=>"2018-10-16T00:00:00.000Z", :dlr=>0.02179786426382509}, + {:date_time=>"2018-10-15T00:00:00.000Z", :dlr=>-0.021617789532325248}, + {:date_time=>"2018-10-12T00:00:00.000Z", :dlr=>0.03509614368752819}, + {:date_time=>"2018-10-11T00:00:00.000Z", :dlr=>-0.008867076040336814}, + {:date_time=>"2018-10-10T00:00:00.000Z", :dlr=>-0.047433479205543055}, + {:date_time=>"2018-10-09T00:00:00.000Z", :dlr=>0.0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 92adaf07235a5ce3da723948b3b676228712f606 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 13 Feb 2019 18:35:41 -0500 Subject: [PATCH 36/84] Add IndicatorValue - Dpo - Dr - Eom - Evm - Fi - Ichimoku - Kc --- lib/technical_analysis/indicators/dpo.rb | 38 ++++-- lib/technical_analysis/indicators/dr.rb | 33 +++-- lib/technical_analysis/indicators/eom.rb | 37 +++-- lib/technical_analysis/indicators/evm.rb | 93 ++++++++++++- lib/technical_analysis/indicators/fi.rb | 35 +++-- lib/technical_analysis/indicators/ichimoku.rb | 88 +++++++----- lib/technical_analysis/indicators/kc.rb | 70 ++++++---- .../technical_analysis/indicators/dpo_spec.rb | 71 +++++----- spec/technical_analysis/indicators/dr_spec.rb | 129 +++++++++--------- .../technical_analysis/indicators/eom_spec.rb | 101 +++++++------- .../technical_analysis/indicators/evm_spec.rb | 101 +++++++------- spec/technical_analysis/indicators/fi_spec.rb | 127 ++++++++--------- .../indicators/ichimoku_spec.rb | 73 +++++----- spec/technical_analysis/indicators/kc_spec.rb | 111 +++++++-------- 14 files changed, 649 insertions(+), 458 deletions(-) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index e59d6c1..8c69367 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Detrended Price Oscillator class Dpo < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(period: 20, **params) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -15.774999999999977}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -19.607999999999976}, - # ] + # @return [Array] def self.calculate(data, period: 20, price_key: :value) period = period.to_i price_key = price_key.to_sym @@ -76,9 +70,10 @@ def self.calculate(data, period: 20, price_key: :value) sma_range = (index - midpoint_index - period + 2)..(index - midpoint_index + 1) midpoint_period_sma = data[sma_range].map { |v| v[price_key] }.average - dop = (current_price - midpoint_period_sma) - - output << { date_time: date_time, value: dop } + dpo = (current_price - midpoint_period_sma) + + output << DpoValue.new(date_time: date_time, dpo: dpo) + index += 1 end @@ -86,4 +81,25 @@ def self.calculate(data, period: 20, price_key: :value) end end + + # The value class to be returned by calculations + class DpoValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the dpo calculation value + attr_accessor :dpo + + def initialize(date_time: nil, dpo: nil) + @date_time = date_time + @dpo = dpo + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, dpo: @dpo } + end + + end end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index db87b6b..a778e8b 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Daily Return class Dr < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 0.01698175787728018}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 0.019063070371121427}, - # ] + # @return [Array] An array of DrValue instances def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) @@ -68,7 +62,7 @@ def self.calculate(data, price_key: :value) data.each do |v| current_price = v[:close].to_f - output << { date_time: v[:date_time], value: ((current_price / prev_price) - 1) } + output << DrValue.new(date_time: v[:date_time], dr: ((current_price / prev_price) - 1)) prev_price = current_price end @@ -77,4 +71,25 @@ def self.calculate(data, price_key: :value) end end + + # The value class to be returned by calculations + class DrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the dr calculation value + attr_accessor :dr + + def initialize(date_time: nil, dr: nil) + @date_time = date_time + @dr = dr + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, dr: @dr } + end + + end end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index ce6e130..1429dc9 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Ease of Movement class Eom < Indicator # Returns the symbol of the technical indicator @@ -41,20 +42,13 @@ def self.min_data_size(period: 14) period.to_i + 1 end - # Calculates the ease of movement (EoM and EVM) for the data over the given period + # Calculates the ease of movement (EoM) for the data over the given period # https://en.wikipedia.org/wiki/Ease_of_movement # # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) - # @param period [Integer] The given period to calculate the EoM / EVM + # @param period [Integer] The given period to calculate the EoM # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -6.497226050937367}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -7.7025655861800235}, - # ] + # @return [Array] An array of EomValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) @@ -74,7 +68,7 @@ def self.calculate(data, period: 14) period_values << emv if period_values.size == period - output << { date_time: v[:date_time], value: period_values.average } + output << EomValue.new(date_time: v[:date_time], eom: period_values.average) period_values.shift end @@ -85,4 +79,25 @@ def self.calculate(data, period: 14) end end + + # The value class to be returned by calculations + class EomValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the eom calculation value + attr_accessor :eom + + def initialize(date_time: nil, eom: nil) + @date_time = date_time + @eom = eom + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, eom: @eom } + end + + end end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index 22d73bc..9ca8bad 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -1,5 +1,6 @@ module TechnicalAnalysis - class Evm < Eom + # Ease of Movement + class Evm < Indicator # Returns the symbol of the technical indicator # @@ -8,5 +9,95 @@ def self.indicator_symbol "evm" end + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator + def self.indicator_name + "Ease of Movement" + end + + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator + def self.valid_options + %i(period) + end + + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided + def self.min_data_size(period: 14) + period.to_i + 1 + end + + # Calculates the ease of movement (EVM) for the data over the given period + # https://en.wikipedia.org/wiki/Ease_of_movement + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) + # @param period [Integer] The given period to calculate the EVM + # + # @return [Array] An array of EvmValue instances + def self.calculate(data, period: 14) + period = period.to_i + Validation.validate_numeric_data(data, :high, :low, :volume) + Validation.validate_length(data, min_data_size(period: period)) + + data = data.sort_by_date_time_asc + + output = [] + period_values = [] + prev_price = data.shift + + data.each do |v| + distance_moved = ((v[:high] + v[:low]) / 2) - ((prev_price[:high] + prev_price[:low]) / 2) + box_ratio = (v[:volume] / 100_000_000.00) / (v[:high] - v[:low]) + emv = distance_moved / box_ratio + + period_values << emv + + if period_values.size == period + output << EvmValue.new(date_time: v[:date_time], evm: period_values.average) + period_values.shift + end + + prev_price = v + end + + output.sort_by_date_time_desc + end + + end + + # The value class to be returned by calculations + class EvmValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the evm calculation value + attr_accessor :evm + + def initialize(date_time: nil, evm: nil) + @date_time = date_time + @evm = evm + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, evm: @evm } + end + end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index 9732fe2..db1250d 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Force Index class Fi < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 115287987.2000001}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 114556606.19999972}, - # ] + # @return [Array] An array of FiValue instances def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) @@ -66,7 +60,9 @@ def self.calculate(data) data.each do |v| fi = ((v[:close] - prev_price[:close]) * v[:volume]) - output << { date_time: v[:date_time], value: fi } + + output << FiValue.new(date_time: v[:date_time], fi: fi) + prev_price = v end @@ -74,4 +70,25 @@ def self.calculate(data) end end + + # The value class to be returned by calculations + class FiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the fi calculation value + attr_accessor :fi + + def initialize(date_time: nil, fi: nil) + @date_time = date_time + @fi = fi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, fi: @fi } + end + + end end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 17cdcc5..33f016f 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Ichimoku Kinko Hyo class Ichimoku < Indicator # Returns the symbol of the technical indicator @@ -54,32 +55,7 @@ def self.min_data_size(medium_period: 26, high_period: 52, **params) # @param medium_period [Integer] The given period to calculate kijun_sen (Base Line), senkou_span_a (Leading Span A), and chikou_span (Lagging Span) # @param high_period [Integer] The given period to calculate senkou_span_b (Leading Span B) # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :chikou_span => 157.17, - # :kijun_sen => 150.68, - # :senkou_span_a => 155.9775, - # :senkou_span_b => 165.765, - # :tenkan_sen => 150.215 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :chikou_span => 146.83, - # :kijun_sen => 150.68, - # :senkou_span_a => 156.965, - # :senkou_span_b => 165.765, - # :tenkan_sen => 147.81 - # } - # }, - # ] + # @return [Array] An array of IchimokuValue instances def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) low_period = low_period.to_i medium_period = medium_period.to_i @@ -101,16 +77,14 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) senkou_span_b = calculate_senkou_span_b(index, medium_period, high_period, data) chikou_span = calculate_chikou_span(index, medium_period, data) - output << { + output << IchimokuValue.new( date_time: date_time, - value: { - tenkan_sen: tenkan_sen, - kijun_sen: kinjun_sen, - senkou_span_a: senkou_span_a, - senkou_span_b: senkou_span_b, - chikou_span: chikou_span - } - } + tenkan_sen: tenkan_sen, + kijun_sen: kinjun_sen, + senkou_span_a: senkou_span_a, + senkou_span_b: senkou_span_b, + chikou_span: chikou_span + ) index += 1 end @@ -157,4 +131,48 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) end end + + # The value class to be returned by calculations + class IchimokuValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the tenkan_sen calculation value + attr_accessor :tenkan_sen + + # @return [Float] the kijun_sen calculation value + attr_accessor :kijun_sen + + # @return [Float] the senkou_span_a calculation value + attr_accessor :senkou_span_a + + # @return [Float] the senkou_span_b calculation value + attr_accessor :senkou_span_b + + # @return [Float] the chikou_span calculation value + attr_accessor :chikou_span + + def initialize(date_time: nil, tenkan_sen: nil, kijun_sen: nil, senkou_span_a: nil, senkou_span_b: nil, chikou_span: nil) + @date_time = date_time + @tenkan_sen = tenkan_sen + @kijun_sen = kijun_sen + @senkou_span_a = senkou_span_a + @senkou_span_b = senkou_span_b + @chikou_span = chikou_span + end + + # @return [Hash] the attributes as a hash + def to_hash + { + date_time: @date_time, + tenkan_sen: @tenkan_sen, + kijun_sen: @kijun_sen, + senkou_span_a: @senkou_span_a, + senkou_span_b: @senkou_span_b, + chikou_span: @chikou_span + } + end + + end end diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index a2157fd..3569893 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Keltner Channel class Kc < Indicator # Returns the symbol of the technical indicator @@ -47,28 +48,7 @@ def self.min_data_size(period: 10) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the KC # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :lower_band => 147.1630066666667, - # :middle_band => 151.9909966666667, - # :upper_band => 156.8189866666667 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :lower_band => 146.74034, - # :middle_band => 151.57433, - # :upper_band => 156.40832 - # } - # } - # ] + # @return [Array] An array of KcValue instances def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -91,14 +71,12 @@ def self.calculate(data, period: 10) ub = mb + trading_range_average lb = mb - trading_range_average - output << { + output << KcValue.new( date_time: v[:date_time], - value: { - middle_band: mb, - upper_band: ub, - lower_band: lb - } - } + lower_band: lb, + middle_band: mb, + upper_band: ub + ) period_values.shift end @@ -108,4 +86,38 @@ def self.calculate(data, period: 10) end end + + # The value class to be returned by calculations + class KcValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the lower_band calculation value + attr_accessor :lower_band + + # @return [Float] the middle_band calculation value + attr_accessor :middle_band + + # @return [Float] the upper_band calculation value + attr_accessor :upper_band + + def initialize(date_time: nil, lower_band: nil, middle_band: nil, upper_band: nil) + @date_time = date_time + @lower_band = lower_band + @middle_band = middle_band + @upper_band = upper_band + end + + # @return [Hash] the attributes as a hash + def to_hash + { + date_time: @date_time, + lower_band: @lower_band, + middle_band: @middle_band, + upper_band: @upper_band + } + end + + end end diff --git a/spec/technical_analysis/indicators/dpo_spec.rb b/spec/technical_analysis/indicators/dpo_spec.rb index c0d262a..56489a7 100644 --- a/spec/technical_analysis/indicators/dpo_spec.rb +++ b/spec/technical_analysis/indicators/dpo_spec.rb @@ -9,45 +9,46 @@ describe 'Detrended Price Oscillator' do it 'Calculates DPO (20 day)' do output = indicator.calculate(input_data, period: 20, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-15.774999999999977}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-19.607999999999976}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-23.730500000000006}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-24.407999999999987}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31.726499999999987}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-17.36949999999996}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-18.922999999999973}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-21.498999999999995}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22.642999999999972}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22.876499999999993}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-35.0085}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-33.053}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-29.025999999999982}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-26.41850000000005}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-22.48350000000005}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-25.746500000000054}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-26.388500000000022}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-22.884000000000043}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-26.35200000000006}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-28.722000000000037}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.836000000000013}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-33.321500000000015}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-29.007000000000033}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-29.3245}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-22.93399999999997}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-30.462999999999965}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-30.723499999999945}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-31.052999999999997}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-39.24899999999997}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-40.02850000000001}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-43.2405}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-39.04850000000002}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-39.16900000000004}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-31.444000000000017} + {:date_time=>"2019-01-09T00:00:00.000Z", :dpo=>-15.774999999999977}, + {:date_time=>"2019-01-08T00:00:00.000Z", :dpo=>-19.607999999999976}, + {:date_time=>"2019-01-07T00:00:00.000Z", :dpo=>-23.730500000000006}, + {:date_time=>"2019-01-04T00:00:00.000Z", :dpo=>-24.407999999999987}, + {:date_time=>"2019-01-03T00:00:00.000Z", :dpo=>-31.726499999999987}, + {:date_time=>"2019-01-02T00:00:00.000Z", :dpo=>-17.36949999999996}, + {:date_time=>"2018-12-31T00:00:00.000Z", :dpo=>-18.922999999999973}, + {:date_time=>"2018-12-28T00:00:00.000Z", :dpo=>-21.498999999999995}, + {:date_time=>"2018-12-27T00:00:00.000Z", :dpo=>-22.642999999999972}, + {:date_time=>"2018-12-26T00:00:00.000Z", :dpo=>-22.876499999999993}, + {:date_time=>"2018-12-24T00:00:00.000Z", :dpo=>-35.0085}, + {:date_time=>"2018-12-21T00:00:00.000Z", :dpo=>-33.053}, + {:date_time=>"2018-12-20T00:00:00.000Z", :dpo=>-29.025999999999982}, + {:date_time=>"2018-12-19T00:00:00.000Z", :dpo=>-26.41850000000005}, + {:date_time=>"2018-12-18T00:00:00.000Z", :dpo=>-22.48350000000005}, + {:date_time=>"2018-12-17T00:00:00.000Z", :dpo=>-25.746500000000054}, + {:date_time=>"2018-12-14T00:00:00.000Z", :dpo=>-26.388500000000022}, + {:date_time=>"2018-12-13T00:00:00.000Z", :dpo=>-22.884000000000043}, + {:date_time=>"2018-12-12T00:00:00.000Z", :dpo=>-26.35200000000006}, + {:date_time=>"2018-12-11T00:00:00.000Z", :dpo=>-28.722000000000037}, + {:date_time=>"2018-12-10T00:00:00.000Z", :dpo=>-29.836000000000013}, + {:date_time=>"2018-12-07T00:00:00.000Z", :dpo=>-33.321500000000015}, + {:date_time=>"2018-12-06T00:00:00.000Z", :dpo=>-29.007000000000033}, + {:date_time=>"2018-12-04T00:00:00.000Z", :dpo=>-29.3245}, + {:date_time=>"2018-12-03T00:00:00.000Z", :dpo=>-22.93399999999997}, + {:date_time=>"2018-11-30T00:00:00.000Z", :dpo=>-30.462999999999965}, + {:date_time=>"2018-11-29T00:00:00.000Z", :dpo=>-30.723499999999945}, + {:date_time=>"2018-11-28T00:00:00.000Z", :dpo=>-31.052999999999997}, + {:date_time=>"2018-11-27T00:00:00.000Z", :dpo=>-39.24899999999997}, + {:date_time=>"2018-11-26T00:00:00.000Z", :dpo=>-40.02850000000001}, + {:date_time=>"2018-11-23T00:00:00.000Z", :dpo=>-43.2405}, + {:date_time=>"2018-11-21T00:00:00.000Z", :dpo=>-39.04850000000002}, + {:date_time=>"2018-11-20T00:00:00.000Z", :dpo=>-39.16900000000004}, + {:date_time=>"2018-11-19T00:00:00.000Z", :dpo=>-31.444000000000017} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/dr_spec.rb b/spec/technical_analysis/indicators/dr_spec.rb index 2232919..4abdeeb 100644 --- a/spec/technical_analysis/indicators/dr_spec.rb +++ b/spec/technical_analysis/indicators/dr_spec.rb @@ -9,74 +9,75 @@ describe 'Daily Return' do it 'Calculates Daily Return' do output = indicator.calculate(input_data, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>0.01698175787728018}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>0.019063070371121427}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.0022258195062726527}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>0.042689359307968244}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.09960739614994929}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>0.0011411182959297772}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>0.009665237150355388}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>0.00051232788984934}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.006489788127505114}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>0.07042157597221266}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.02587407947986453}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.038895619460562525}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.025234632357511222}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.031191666164870235}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>0.01299255825301926}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.009306260575296044}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.031997660134542305}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>0.010940272028385545}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>0.0027871671707289103}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.005719339622641484}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>0.006587928066947413}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-0.03565705128205121}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-0.011149470824608043}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-0.043988745806730845}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>0.03494232276850706}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-0.005402394876079075}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-0.0076821045650491415}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>0.038452708907254385}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-0.0021761539342571856}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>0.013523710023797264}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-0.025398800769317886}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-0.0011300711944851605}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-0.047777897342085596}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-0.03963209838267967}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>0.011075701374013924}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>0.02467880085653107}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-0.02824741195442948}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-0.009991244785497289}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-0.05037413801535684}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-0.019281500311765565}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-0.006954036675398845}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>0.030328311331403013}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>0.010814028473634663}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-0.028388278388278287}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-0.06633066330663306}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>0.015352279996344587}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>0.026066572902015972}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>0.004994346023369678}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-0.018770226537216828}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-0.015923566878980888}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>0.021897810218978186}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-0.034301620796480026}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>0.009426693859052815}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>0.006110072500113972}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>0.015230071289695335}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-0.023373570233735652}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-0.004321404456448352}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>0.022037173352962736}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-0.021385799828913643}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>0.035719281883889176}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-0.00882787946015906}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-0.046326089831180806}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0.0} + {:date_time=>"2019-01-09T00:00:00.000Z", :dr=>0.01698175787728018}, + {:date_time=>"2019-01-08T00:00:00.000Z", :dr=>0.019063070371121427}, + {:date_time=>"2019-01-07T00:00:00.000Z", :dr=>-0.0022258195062726527}, + {:date_time=>"2019-01-04T00:00:00.000Z", :dr=>0.042689359307968244}, + {:date_time=>"2019-01-03T00:00:00.000Z", :dr=>-0.09960739614994929}, + {:date_time=>"2019-01-02T00:00:00.000Z", :dr=>0.0011411182959297772}, + {:date_time=>"2018-12-31T00:00:00.000Z", :dr=>0.009665237150355388}, + {:date_time=>"2018-12-28T00:00:00.000Z", :dr=>0.00051232788984934}, + {:date_time=>"2018-12-27T00:00:00.000Z", :dr=>-0.006489788127505114}, + {:date_time=>"2018-12-26T00:00:00.000Z", :dr=>0.07042157597221266}, + {:date_time=>"2018-12-24T00:00:00.000Z", :dr=>-0.02587407947986453}, + {:date_time=>"2018-12-21T00:00:00.000Z", :dr=>-0.038895619460562525}, + {:date_time=>"2018-12-20T00:00:00.000Z", :dr=>-0.025234632357511222}, + {:date_time=>"2018-12-19T00:00:00.000Z", :dr=>-0.031191666164870235}, + {:date_time=>"2018-12-18T00:00:00.000Z", :dr=>0.01299255825301926}, + {:date_time=>"2018-12-17T00:00:00.000Z", :dr=>-0.009306260575296044}, + {:date_time=>"2018-12-14T00:00:00.000Z", :dr=>-0.031997660134542305}, + {:date_time=>"2018-12-13T00:00:00.000Z", :dr=>0.010940272028385545}, + {:date_time=>"2018-12-12T00:00:00.000Z", :dr=>0.0027871671707289103}, + {:date_time=>"2018-12-11T00:00:00.000Z", :dr=>-0.005719339622641484}, + {:date_time=>"2018-12-10T00:00:00.000Z", :dr=>0.006587928066947413}, + {:date_time=>"2018-12-07T00:00:00.000Z", :dr=>-0.03565705128205121}, + {:date_time=>"2018-12-06T00:00:00.000Z", :dr=>-0.011149470824608043}, + {:date_time=>"2018-12-04T00:00:00.000Z", :dr=>-0.043988745806730845}, + {:date_time=>"2018-12-03T00:00:00.000Z", :dr=>0.03494232276850706}, + {:date_time=>"2018-11-30T00:00:00.000Z", :dr=>-0.005402394876079075}, + {:date_time=>"2018-11-29T00:00:00.000Z", :dr=>-0.0076821045650491415}, + {:date_time=>"2018-11-28T00:00:00.000Z", :dr=>0.038452708907254385}, + {:date_time=>"2018-11-27T00:00:00.000Z", :dr=>-0.0021761539342571856}, + {:date_time=>"2018-11-26T00:00:00.000Z", :dr=>0.013523710023797264}, + {:date_time=>"2018-11-23T00:00:00.000Z", :dr=>-0.025398800769317886}, + {:date_time=>"2018-11-21T00:00:00.000Z", :dr=>-0.0011300711944851605}, + {:date_time=>"2018-11-20T00:00:00.000Z", :dr=>-0.047777897342085596}, + {:date_time=>"2018-11-19T00:00:00.000Z", :dr=>-0.03963209838267967}, + {:date_time=>"2018-11-16T00:00:00.000Z", :dr=>0.011075701374013924}, + {:date_time=>"2018-11-15T00:00:00.000Z", :dr=>0.02467880085653107}, + {:date_time=>"2018-11-14T00:00:00.000Z", :dr=>-0.02824741195442948}, + {:date_time=>"2018-11-13T00:00:00.000Z", :dr=>-0.009991244785497289}, + {:date_time=>"2018-11-12T00:00:00.000Z", :dr=>-0.05037413801535684}, + {:date_time=>"2018-11-09T00:00:00.000Z", :dr=>-0.019281500311765565}, + {:date_time=>"2018-11-08T00:00:00.000Z", :dr=>-0.006954036675398845}, + {:date_time=>"2018-11-07T00:00:00.000Z", :dr=>0.030328311331403013}, + {:date_time=>"2018-11-06T00:00:00.000Z", :dr=>0.010814028473634663}, + {:date_time=>"2018-11-05T00:00:00.000Z", :dr=>-0.028388278388278287}, + {:date_time=>"2018-11-02T00:00:00.000Z", :dr=>-0.06633066330663306}, + {:date_time=>"2018-11-01T00:00:00.000Z", :dr=>0.015352279996344587}, + {:date_time=>"2018-10-31T00:00:00.000Z", :dr=>0.026066572902015972}, + {:date_time=>"2018-10-30T00:00:00.000Z", :dr=>0.004994346023369678}, + {:date_time=>"2018-10-29T00:00:00.000Z", :dr=>-0.018770226537216828}, + {:date_time=>"2018-10-26T00:00:00.000Z", :dr=>-0.015923566878980888}, + {:date_time=>"2018-10-25T00:00:00.000Z", :dr=>0.021897810218978186}, + {:date_time=>"2018-10-24T00:00:00.000Z", :dr=>-0.034301620796480026}, + {:date_time=>"2018-10-23T00:00:00.000Z", :dr=>0.009426693859052815}, + {:date_time=>"2018-10-22T00:00:00.000Z", :dr=>0.006110072500113972}, + {:date_time=>"2018-10-19T00:00:00.000Z", :dr=>0.015230071289695335}, + {:date_time=>"2018-10-18T00:00:00.000Z", :dr=>-0.023373570233735652}, + {:date_time=>"2018-10-17T00:00:00.000Z", :dr=>-0.004321404456448352}, + {:date_time=>"2018-10-16T00:00:00.000Z", :dr=>0.022037173352962736}, + {:date_time=>"2018-10-15T00:00:00.000Z", :dr=>-0.021385799828913643}, + {:date_time=>"2018-10-12T00:00:00.000Z", :dr=>0.035719281883889176}, + {:date_time=>"2018-10-11T00:00:00.000Z", :dr=>-0.00882787946015906}, + {:date_time=>"2018-10-10T00:00:00.000Z", :dr=>-0.046326089831180806}, + {:date_time=>"2018-10-09T00:00:00.000Z", :dr=>0.0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/eom_spec.rb b/spec/technical_analysis/indicators/eom_spec.rb index 5db67b6..5e2c840 100644 --- a/spec/technical_analysis/indicators/eom_spec.rb +++ b/spec/technical_analysis/indicators/eom_spec.rb @@ -9,60 +9,61 @@ describe 'Ease of Movement' do it 'Calculates EoM (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814} + {:date_time=>"2019-01-09T00:00:00.000Z", :eom=>-6.497226050937367}, + {:date_time=>"2019-01-08T00:00:00.000Z", :eom=>-7.7025655861800235}, + {:date_time=>"2019-01-07T00:00:00.000Z", :eom=>-10.852331038262774}, + {:date_time=>"2019-01-04T00:00:00.000Z", :eom=>-13.901372232239117}, + {:date_time=>"2019-01-03T00:00:00.000Z", :eom=>-14.868322149693872}, + {:date_time=>"2019-01-02T00:00:00.000Z", :eom=>-10.542472341445862}, + {:date_time=>"2018-12-31T00:00:00.000Z", :eom=>-7.266128029998595}, + {:date_time=>"2018-12-28T00:00:00.000Z", :eom=>-11.754905920393293}, + {:date_time=>"2018-12-27T00:00:00.000Z", :eom=>-15.149439471732872}, + {:date_time=>"2018-12-26T00:00:00.000Z", :eom=>-21.397258702024285}, + {:date_time=>"2018-12-24T00:00:00.000Z", :eom=>-29.127850557035778}, + {:date_time=>"2018-12-21T00:00:00.000Z", :eom=>-21.640253827328284}, + {:date_time=>"2018-12-20T00:00:00.000Z", :eom=>-19.510117531121228}, + {:date_time=>"2018-12-19T00:00:00.000Z", :eom=>-14.184550665717635}, + {:date_time=>"2018-12-18T00:00:00.000Z", :eom=>-5.583810139052782}, + {:date_time=>"2018-12-17T00:00:00.000Z", :eom=>-5.714363954096145}, + {:date_time=>"2018-12-14T00:00:00.000Z", :eom=>-5.49920090817078}, + {:date_time=>"2018-12-13T00:00:00.000Z", :eom=>-8.427863395925653}, + {:date_time=>"2018-12-12T00:00:00.000Z", :eom=>-8.897024349696329}, + {:date_time=>"2018-12-11T00:00:00.000Z", :eom=>-15.409243349973261}, + {:date_time=>"2018-12-10T00:00:00.000Z", :eom=>-21.68916026908629}, + {:date_time=>"2018-12-07T00:00:00.000Z", :eom=>-15.003602992747133}, + {:date_time=>"2018-12-06T00:00:00.000Z", :eom=>-14.327931101318542}, + {:date_time=>"2018-12-04T00:00:00.000Z", :eom=>-13.565693513893978}, + {:date_time=>"2018-12-03T00:00:00.000Z", :eom=>-11.780616477806618}, + {:date_time=>"2018-11-30T00:00:00.000Z", :eom=>-20.874548142667777}, + {:date_time=>"2018-11-29T00:00:00.000Z", :eom=>-23.304959556064855}, + {:date_time=>"2018-11-28T00:00:00.000Z", :eom=>-23.906907831421474}, + {:date_time=>"2018-11-27T00:00:00.000Z", :eom=>-24.18360420308819}, + {:date_time=>"2018-11-26T00:00:00.000Z", :eom=>-23.02094878061384}, + {:date_time=>"2018-11-23T00:00:00.000Z", :eom=>-27.26817615617346}, + {:date_time=>"2018-11-21T00:00:00.000Z", :eom=>-28.2247053700715}, + {:date_time=>"2018-11-20T00:00:00.000Z", :eom=>-27.37028760395389}, + {:date_time=>"2018-11-19T00:00:00.000Z", :eom=>-16.94506299946587}, + {:date_time=>"2018-11-16T00:00:00.000Z", :eom=>-13.43297156412281}, + {:date_time=>"2018-11-15T00:00:00.000Z", :eom=>-23.978202090280167}, + {:date_time=>"2018-11-14T00:00:00.000Z", :eom=>-26.374761082588922}, + {:date_time=>"2018-11-13T00:00:00.000Z", :eom=>-22.593717509723117}, + {:date_time=>"2018-11-12T00:00:00.000Z", :eom=>-19.69000228424736}, + {:date_time=>"2018-11-09T00:00:00.000Z", :eom=>-16.918604972309158}, + {:date_time=>"2018-11-08T00:00:00.000Z", :eom=>-11.567473480653877}, + {:date_time=>"2018-11-07T00:00:00.000Z", :eom=>-10.367227984759097}, + {:date_time=>"2018-11-06T00:00:00.000Z", :eom=>-22.183583990006944}, + {:date_time=>"2018-11-05T00:00:00.000Z", :eom=>-22.338003197707696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :eom=>-16.2797807192085}, + {:date_time=>"2018-11-01T00:00:00.000Z", :eom=>-10.135395436615527}, + {:date_time=>"2018-10-31T00:00:00.000Z", :eom=>-6.606596973217312}, + {:date_time=>"2018-10-30T00:00:00.000Z", :eom=>-16.275660385464448}, + {:date_time=>"2018-10-29T00:00:00.000Z", :eom=>-21.877975231994814} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb index 8e05224..9267331 100644 --- a/spec/technical_analysis/indicators/evm_spec.rb +++ b/spec/technical_analysis/indicators/evm_spec.rb @@ -9,60 +9,61 @@ describe 'Ease of Movement' do it 'Calculates EVM (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-6.497226050937367}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-7.7025655861800235}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-10.852331038262774}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-13.901372232239117}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-14.868322149693872}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-10.542472341445862}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-7.266128029998595}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-11.754905920393293}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-15.149439471732872}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-21.397258702024285}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-29.127850557035778}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-21.640253827328284}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-19.510117531121228}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-14.184550665717635}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-5.583810139052782}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-5.714363954096145}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-5.49920090817078}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-8.427863395925653}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-8.897024349696329}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-15.409243349973261}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-21.68916026908629}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-15.003602992747133}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-14.327931101318542}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-13.565693513893978}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-11.780616477806618}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-20.874548142667777}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-23.304959556064855}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-23.906907831421474}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-24.18360420308819}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-23.02094878061384}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-27.26817615617346}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-28.2247053700715}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-27.37028760395389}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-16.94506299946587}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-13.43297156412281}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-23.978202090280167}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-26.374761082588922}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-22.593717509723117}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-19.69000228424736}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-16.918604972309158}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-11.567473480653877}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-10.367227984759097}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-22.183583990006944}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-22.338003197707696}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-16.2797807192085}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-10.135395436615527}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-6.606596973217312}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-16.275660385464448}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-21.877975231994814} + {:date_time=>"2019-01-09T00:00:00.000Z", :evm=>-6.497226050937367}, + {:date_time=>"2019-01-08T00:00:00.000Z", :evm=>-7.7025655861800235}, + {:date_time=>"2019-01-07T00:00:00.000Z", :evm=>-10.852331038262774}, + {:date_time=>"2019-01-04T00:00:00.000Z", :evm=>-13.901372232239117}, + {:date_time=>"2019-01-03T00:00:00.000Z", :evm=>-14.868322149693872}, + {:date_time=>"2019-01-02T00:00:00.000Z", :evm=>-10.542472341445862}, + {:date_time=>"2018-12-31T00:00:00.000Z", :evm=>-7.266128029998595}, + {:date_time=>"2018-12-28T00:00:00.000Z", :evm=>-11.754905920393293}, + {:date_time=>"2018-12-27T00:00:00.000Z", :evm=>-15.149439471732872}, + {:date_time=>"2018-12-26T00:00:00.000Z", :evm=>-21.397258702024285}, + {:date_time=>"2018-12-24T00:00:00.000Z", :evm=>-29.127850557035778}, + {:date_time=>"2018-12-21T00:00:00.000Z", :evm=>-21.640253827328284}, + {:date_time=>"2018-12-20T00:00:00.000Z", :evm=>-19.510117531121228}, + {:date_time=>"2018-12-19T00:00:00.000Z", :evm=>-14.184550665717635}, + {:date_time=>"2018-12-18T00:00:00.000Z", :evm=>-5.583810139052782}, + {:date_time=>"2018-12-17T00:00:00.000Z", :evm=>-5.714363954096145}, + {:date_time=>"2018-12-14T00:00:00.000Z", :evm=>-5.49920090817078}, + {:date_time=>"2018-12-13T00:00:00.000Z", :evm=>-8.427863395925653}, + {:date_time=>"2018-12-12T00:00:00.000Z", :evm=>-8.897024349696329}, + {:date_time=>"2018-12-11T00:00:00.000Z", :evm=>-15.409243349973261}, + {:date_time=>"2018-12-10T00:00:00.000Z", :evm=>-21.68916026908629}, + {:date_time=>"2018-12-07T00:00:00.000Z", :evm=>-15.003602992747133}, + {:date_time=>"2018-12-06T00:00:00.000Z", :evm=>-14.327931101318542}, + {:date_time=>"2018-12-04T00:00:00.000Z", :evm=>-13.565693513893978}, + {:date_time=>"2018-12-03T00:00:00.000Z", :evm=>-11.780616477806618}, + {:date_time=>"2018-11-30T00:00:00.000Z", :evm=>-20.874548142667777}, + {:date_time=>"2018-11-29T00:00:00.000Z", :evm=>-23.304959556064855}, + {:date_time=>"2018-11-28T00:00:00.000Z", :evm=>-23.906907831421474}, + {:date_time=>"2018-11-27T00:00:00.000Z", :evm=>-24.18360420308819}, + {:date_time=>"2018-11-26T00:00:00.000Z", :evm=>-23.02094878061384}, + {:date_time=>"2018-11-23T00:00:00.000Z", :evm=>-27.26817615617346}, + {:date_time=>"2018-11-21T00:00:00.000Z", :evm=>-28.2247053700715}, + {:date_time=>"2018-11-20T00:00:00.000Z", :evm=>-27.37028760395389}, + {:date_time=>"2018-11-19T00:00:00.000Z", :evm=>-16.94506299946587}, + {:date_time=>"2018-11-16T00:00:00.000Z", :evm=>-13.43297156412281}, + {:date_time=>"2018-11-15T00:00:00.000Z", :evm=>-23.978202090280167}, + {:date_time=>"2018-11-14T00:00:00.000Z", :evm=>-26.374761082588922}, + {:date_time=>"2018-11-13T00:00:00.000Z", :evm=>-22.593717509723117}, + {:date_time=>"2018-11-12T00:00:00.000Z", :evm=>-19.69000228424736}, + {:date_time=>"2018-11-09T00:00:00.000Z", :evm=>-16.918604972309158}, + {:date_time=>"2018-11-08T00:00:00.000Z", :evm=>-11.567473480653877}, + {:date_time=>"2018-11-07T00:00:00.000Z", :evm=>-10.367227984759097}, + {:date_time=>"2018-11-06T00:00:00.000Z", :evm=>-22.183583990006944}, + {:date_time=>"2018-11-05T00:00:00.000Z", :evm=>-22.338003197707696}, + {:date_time=>"2018-11-02T00:00:00.000Z", :evm=>-16.2797807192085}, + {:date_time=>"2018-11-01T00:00:00.000Z", :evm=>-10.135395436615527}, + {:date_time=>"2018-10-31T00:00:00.000Z", :evm=>-6.606596973217312}, + {:date_time=>"2018-10-30T00:00:00.000Z", :evm=>-16.275660385464448}, + {:date_time=>"2018-10-29T00:00:00.000Z", :evm=>-21.877975231994814} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/fi_spec.rb b/spec/technical_analysis/indicators/fi_spec.rb index 0b8a40a..dd9b6c2 100644 --- a/spec/technical_analysis/indicators/fi_spec.rb +++ b/spec/technical_analysis/indicators/fi_spec.rb @@ -9,73 +9,74 @@ describe 'Forced Index' do it 'Calculates FI' do output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>115287987.2000001}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>114556606.19999972}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-18008575.19999913}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>348561555.4999996}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-1433110593.199999}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>6414672.59999923}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>52094078.90000067}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>3339247.9999993355}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-52641026.99999906}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>601104008.9999986}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-144959996.99999917}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-582537190.0000021}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-261456813.7999983}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-246555930.60000032}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>71894933.69999984}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-66605646.799999654}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-222193369.19999996}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>58745288.49999982}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>16673099.59999996}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-44588998.799999945}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>68552489.99999909}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-259658176.39999956}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-84128672.69999996}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-334478362.4999998}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>252955247.99999923}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-38241532.19999996}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-57717776.19999944}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>307809724.99999946}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-15639333.199999813}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>104063205.60000056}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-106071625.30000022}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-6219247.999999646}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-600986678.4000016}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-319277709.3999995}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>76725619.60000016}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>213312352.5999993}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-328772056.1999987}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-90647877.39999989}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-525207609.0000006}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-137957395.20000035}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-36922334.19999948}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>205742335.19999927}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>69268889.60000022}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-389165081.2999991}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-1342026294.4000008}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>177925675.1999992}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>211373463.60000008}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>38677205.80000009}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-185597581.4000001}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-165170950.0}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>136718771.40000024}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-305539796.7999995}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>80456833.59999938}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>38527063.6000001}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>108156545.69999973}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-167452577.5999996}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-21785164.80000018}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>137964214.49999976}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-143832137.5}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>302529938.200001}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-101043431.20000133}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-431793575.69999963} + {:date_time=>"2019-01-09T00:00:00.000Z", :fi=>115287987.2000001}, + {:date_time=>"2019-01-08T00:00:00.000Z", :fi=>114556606.19999972}, + {:date_time=>"2019-01-07T00:00:00.000Z", :fi=>-18008575.19999913}, + {:date_time=>"2019-01-04T00:00:00.000Z", :fi=>348561555.4999996}, + {:date_time=>"2019-01-03T00:00:00.000Z", :fi=>-1433110593.199999}, + {:date_time=>"2019-01-02T00:00:00.000Z", :fi=>6414672.59999923}, + {:date_time=>"2018-12-31T00:00:00.000Z", :fi=>52094078.90000067}, + {:date_time=>"2018-12-28T00:00:00.000Z", :fi=>3339247.9999993355}, + {:date_time=>"2018-12-27T00:00:00.000Z", :fi=>-52641026.99999906}, + {:date_time=>"2018-12-26T00:00:00.000Z", :fi=>601104008.9999986}, + {:date_time=>"2018-12-24T00:00:00.000Z", :fi=>-144959996.99999917}, + {:date_time=>"2018-12-21T00:00:00.000Z", :fi=>-582537190.0000021}, + {:date_time=>"2018-12-20T00:00:00.000Z", :fi=>-261456813.7999983}, + {:date_time=>"2018-12-19T00:00:00.000Z", :fi=>-246555930.60000032}, + {:date_time=>"2018-12-18T00:00:00.000Z", :fi=>71894933.69999984}, + {:date_time=>"2018-12-17T00:00:00.000Z", :fi=>-66605646.799999654}, + {:date_time=>"2018-12-14T00:00:00.000Z", :fi=>-222193369.19999996}, + {:date_time=>"2018-12-13T00:00:00.000Z", :fi=>58745288.49999982}, + {:date_time=>"2018-12-12T00:00:00.000Z", :fi=>16673099.59999996}, + {:date_time=>"2018-12-11T00:00:00.000Z", :fi=>-44588998.799999945}, + {:date_time=>"2018-12-10T00:00:00.000Z", :fi=>68552489.99999909}, + {:date_time=>"2018-12-07T00:00:00.000Z", :fi=>-259658176.39999956}, + {:date_time=>"2018-12-06T00:00:00.000Z", :fi=>-84128672.69999996}, + {:date_time=>"2018-12-04T00:00:00.000Z", :fi=>-334478362.4999998}, + {:date_time=>"2018-12-03T00:00:00.000Z", :fi=>252955247.99999923}, + {:date_time=>"2018-11-30T00:00:00.000Z", :fi=>-38241532.19999996}, + {:date_time=>"2018-11-29T00:00:00.000Z", :fi=>-57717776.19999944}, + {:date_time=>"2018-11-28T00:00:00.000Z", :fi=>307809724.99999946}, + {:date_time=>"2018-11-27T00:00:00.000Z", :fi=>-15639333.199999813}, + {:date_time=>"2018-11-26T00:00:00.000Z", :fi=>104063205.60000056}, + {:date_time=>"2018-11-23T00:00:00.000Z", :fi=>-106071625.30000022}, + {:date_time=>"2018-11-21T00:00:00.000Z", :fi=>-6219247.999999646}, + {:date_time=>"2018-11-20T00:00:00.000Z", :fi=>-600986678.4000016}, + {:date_time=>"2018-11-19T00:00:00.000Z", :fi=>-319277709.3999995}, + {:date_time=>"2018-11-16T00:00:00.000Z", :fi=>76725619.60000016}, + {:date_time=>"2018-11-15T00:00:00.000Z", :fi=>213312352.5999993}, + {:date_time=>"2018-11-14T00:00:00.000Z", :fi=>-328772056.1999987}, + {:date_time=>"2018-11-13T00:00:00.000Z", :fi=>-90647877.39999989}, + {:date_time=>"2018-11-12T00:00:00.000Z", :fi=>-525207609.0000006}, + {:date_time=>"2018-11-09T00:00:00.000Z", :fi=>-137957395.20000035}, + {:date_time=>"2018-11-08T00:00:00.000Z", :fi=>-36922334.19999948}, + {:date_time=>"2018-11-07T00:00:00.000Z", :fi=>205742335.19999927}, + {:date_time=>"2018-11-06T00:00:00.000Z", :fi=>69268889.60000022}, + {:date_time=>"2018-11-05T00:00:00.000Z", :fi=>-389165081.2999991}, + {:date_time=>"2018-11-02T00:00:00.000Z", :fi=>-1342026294.4000008}, + {:date_time=>"2018-11-01T00:00:00.000Z", :fi=>177925675.1999992}, + {:date_time=>"2018-10-31T00:00:00.000Z", :fi=>211373463.60000008}, + {:date_time=>"2018-10-30T00:00:00.000Z", :fi=>38677205.80000009}, + {:date_time=>"2018-10-29T00:00:00.000Z", :fi=>-185597581.4000001}, + {:date_time=>"2018-10-26T00:00:00.000Z", :fi=>-165170950.0}, + {:date_time=>"2018-10-25T00:00:00.000Z", :fi=>136718771.40000024}, + {:date_time=>"2018-10-24T00:00:00.000Z", :fi=>-305539796.7999995}, + {:date_time=>"2018-10-23T00:00:00.000Z", :fi=>80456833.59999938}, + {:date_time=>"2018-10-22T00:00:00.000Z", :fi=>38527063.6000001}, + {:date_time=>"2018-10-19T00:00:00.000Z", :fi=>108156545.69999973}, + {:date_time=>"2018-10-18T00:00:00.000Z", :fi=>-167452577.5999996}, + {:date_time=>"2018-10-17T00:00:00.000Z", :fi=>-21785164.80000018}, + {:date_time=>"2018-10-16T00:00:00.000Z", :fi=>137964214.49999976}, + {:date_time=>"2018-10-15T00:00:00.000Z", :fi=>-143832137.5}, + {:date_time=>"2018-10-12T00:00:00.000Z", :fi=>302529938.200001}, + {:date_time=>"2018-10-11T00:00:00.000Z", :fi=>-101043431.20000133}, + {:date_time=>"2018-10-10T00:00:00.000Z", :fi=>-431793575.69999963} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb index 0653c11..3e308a6 100644 --- a/spec/technical_analysis/indicators/ichimoku_spec.rb +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -9,46 +9,47 @@ describe 'Ichimoku' do it 'Calculates Ichimoku' do output = indicator.calculate(input_data, low_period: 3, medium_period: 10, high_period: 20) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:chikou_span=>146.83, :kijun_sen=>150.68, :senkou_span_a=>156.965, :senkou_span_b=>165.765, :tenkan_sen=>147.81}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:chikou_span=>150.73, :kijun_sen=>150.68, :senkou_span_a=>159.82, :senkou_span_b=>167.285, :tenkan_sen=>145.41500000000002}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:chikou_span=>156.83, :kijun_sen=>152.055, :senkou_span_a=>163.15500000000003, :senkou_span_b=>170.12, :tenkan_sen=>150.425}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:chikou_span=>160.89, :kijun_sen=>154.725, :senkou_span_a=>165.3275, :senkou_span_b=>172.015, :tenkan_sen=>150.68}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:chikou_span=>166.07, :kijun_sen=>157.06, :senkou_span_a=>169.23247500000002, :senkou_span_b=>176.71499999999997, :tenkan_sen=>156.79500000000002}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:chikou_span=>163.94, :kijun_sen=>157.47, :senkou_span_a=>170.74249999999998, :senkou_span_b=>178.84975, :tenkan_sen=>154.715}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:chikou_span=>165.48, :kijun_sen=>157.835, :senkou_span_a=>171.53, :senkou_span_b=>179.14975, :tenkan_sen=>152.62}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:chikou_span=>170.95, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.95999999999998, :senkou_span_b=>179.14975, :tenkan_sen=>151.91}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:chikou_span=>169.1, :kijun_sen=>159.57999999999998, :senkou_span_a=>170.88, :senkou_span_b=>180.255, :tenkan_sen=>152.375}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:chikou_span=>168.63, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.5225, :senkou_span_b=>181.59, :tenkan_sen=>154.35000000000002}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:chikou_span=>169.6, :kijun_sen=>161.1, :senkou_span_a=>171.595, :senkou_span_b=>184.67000000000002, :tenkan_sen=>158.54}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:chikou_span=>168.49, :kijun_sen=>164.895, :senkou_span_a=>175.98247500000002, :senkou_span_b=>189.21, :tenkan_sen=>161.41500000000002}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:chikou_span=>174.72, :kijun_sen=>166.935, :senkou_span_a=>177.64, :senkou_span_b=>190.19, :tenkan_sen=>163.72}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:chikou_span=>176.69, :kijun_sen=>172.55995000000001, :senkou_span_a=>179.10250000000002, :senkou_span_b=>190.19, :tenkan_sen=>165.905}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:chikou_span=>184.82, :kijun_sen=>173.83499999999998, :senkou_span_a=>180.73250000000002, :senkou_span_b=>190.19, :tenkan_sen=>167.64999999999998}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:chikou_span=>178.58, :kijun_sen=>174.135, :senkou_span_a=>180.739875, :senkou_span_b=>191.95499999999998, :tenkan_sen=>168.925}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:chikou_span=>179.55, :kijun_sen=>174.135, :senkou_span_a=>179.727375, :senkou_span_b=>196.31, :tenkan_sen=>169.785}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:chikou_span=>180.94, :kijun_sen=>174.135, :senkou_span_a=>179.194875, :senkou_span_b=>196.31, :tenkan_sen=>167.625}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:chikou_span=>174.24, :kijun_sen=>174.135, :senkou_span_a=>178.57375000000002, :senkou_span_b=>196.31, :tenkan_sen=>168.91000000000003}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:chikou_span=>174.62, :kijun_sen=>174.135, :senkou_span_a=>180.16, :senkou_span_b=>196.31, :tenkan_sen=>169.055}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:chikou_span=>172.29, :kijun_sen=>176.62, :senkou_span_a=>182.92000000000002, :senkou_span_b=>197.23000000000002, :tenkan_sen=>175.34495}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:chikou_span=>176.78, :kijun_sen=>177.6, :senkou_span_a=>187.95999999999998, :senkou_span_b=>198.935, :tenkan_sen=>177.68}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:chikou_span=>176.98, :kijun_sen=>177.6, :senkou_span_a=>189.027375, :senkou_span_b=>199.87, :tenkan_sen=>180.60500000000002}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:chikou_span=>185.86, :kijun_sen=>180.48, :senkou_span_a=>193.76737500000002, :senkou_span_b=>204.61, :tenkan_sen=>180.985}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:chikou_span=>193.53, :kijun_sen=>182.61475000000002, :senkou_span_a=>194.237375, :senkou_span_b=>205.07999999999998, :tenkan_sen=>178.865}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:chikou_span=>191.41, :kijun_sen=>182.61475000000002, :senkou_span_a=>195.6725, :senkou_span_b=>205.07999999999998, :tenkan_sen=>176.84}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:chikou_span=>186.8, :kijun_sen=>182.61475000000002, :senkou_span_a=>198.51749999999998, :senkou_span_b=>205.07999999999998, :tenkan_sen=>175.77499999999998}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:chikou_span=>192.23, :kijun_sen=>183.72, :senkou_span_a=>202.81755, :senkou_span_b=>207.84005, :tenkan_sen=>173.4275}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:chikou_span=>194.17, :kijun_sen=>185.055, :senkou_span_a=>205.015, :senkou_span_b=>209.01, :tenkan_sen=>175.265}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:chikou_span=>204.47, :kijun_sen=>189.055, :senkou_span_a=>208.225, :senkou_span_b=>211.2, :tenkan_sen=>176.785}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:chikou_span=>208.49, :kijun_sen=>192.815, :senkou_span_a=>208.08499999999998, :senkou_span_b=>211.2, :tenkan_sen=>183.105}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:chikou_span=>209.95, :kijun_sen=>192.815, :senkou_span_a=>207.19, :senkou_span_b=>211.2, :tenkan_sen=>185.23975000000002}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:chikou_span=>203.77, :kijun_sen=>197.555, :senkou_span_a=>208.555, :senkou_span_b=>212.26, :tenkan_sen=>189.97975000000002}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:chikou_span=>201.59, :kijun_sen=>198.025, :senkou_span_a=>210.7325, :senkou_span_b=>212.72, :tenkan_sen=>190.44975}} + {:date_time=>"2019-01-09T00:00:00.000Z", :chikou_span=>157.17, :kijun_sen=>150.68, :senkou_span_a=>155.9775, :senkou_span_b=>165.765, :tenkan_sen=>150.215}, + {:date_time=>"2019-01-08T00:00:00.000Z", :chikou_span=>146.83, :kijun_sen=>150.68, :senkou_span_a=>156.965, :senkou_span_b=>165.765, :tenkan_sen=>147.81}, + {:date_time=>"2019-01-07T00:00:00.000Z", :chikou_span=>150.73, :kijun_sen=>150.68, :senkou_span_a=>159.82, :senkou_span_b=>167.285, :tenkan_sen=>145.41500000000002}, + {:date_time=>"2019-01-04T00:00:00.000Z", :chikou_span=>156.83, :kijun_sen=>152.055, :senkou_span_a=>163.15500000000003, :senkou_span_b=>170.12, :tenkan_sen=>150.425}, + {:date_time=>"2019-01-03T00:00:00.000Z", :chikou_span=>160.89, :kijun_sen=>154.725, :senkou_span_a=>165.3275, :senkou_span_b=>172.015, :tenkan_sen=>150.68}, + {:date_time=>"2019-01-02T00:00:00.000Z", :chikou_span=>166.07, :kijun_sen=>157.06, :senkou_span_a=>169.23247500000002, :senkou_span_b=>176.71499999999997, :tenkan_sen=>156.79500000000002}, + {:date_time=>"2018-12-31T00:00:00.000Z", :chikou_span=>163.94, :kijun_sen=>157.47, :senkou_span_a=>170.74249999999998, :senkou_span_b=>178.84975, :tenkan_sen=>154.715}, + {:date_time=>"2018-12-28T00:00:00.000Z", :chikou_span=>165.48, :kijun_sen=>157.835, :senkou_span_a=>171.53, :senkou_span_b=>179.14975, :tenkan_sen=>152.62}, + {:date_time=>"2018-12-27T00:00:00.000Z", :chikou_span=>170.95, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.95999999999998, :senkou_span_b=>179.14975, :tenkan_sen=>151.91}, + {:date_time=>"2018-12-26T00:00:00.000Z", :chikou_span=>169.1, :kijun_sen=>159.57999999999998, :senkou_span_a=>170.88, :senkou_span_b=>180.255, :tenkan_sen=>152.375}, + {:date_time=>"2018-12-24T00:00:00.000Z", :chikou_span=>168.63, :kijun_sen=>159.57999999999998, :senkou_span_a=>171.5225, :senkou_span_b=>181.59, :tenkan_sen=>154.35000000000002}, + {:date_time=>"2018-12-21T00:00:00.000Z", :chikou_span=>169.6, :kijun_sen=>161.1, :senkou_span_a=>171.595, :senkou_span_b=>184.67000000000002, :tenkan_sen=>158.54}, + {:date_time=>"2018-12-20T00:00:00.000Z", :chikou_span=>168.49, :kijun_sen=>164.895, :senkou_span_a=>175.98247500000002, :senkou_span_b=>189.21, :tenkan_sen=>161.41500000000002}, + {:date_time=>"2018-12-19T00:00:00.000Z", :chikou_span=>174.72, :kijun_sen=>166.935, :senkou_span_a=>177.64, :senkou_span_b=>190.19, :tenkan_sen=>163.72}, + {:date_time=>"2018-12-18T00:00:00.000Z", :chikou_span=>176.69, :kijun_sen=>172.55995000000001, :senkou_span_a=>179.10250000000002, :senkou_span_b=>190.19, :tenkan_sen=>165.905}, + {:date_time=>"2018-12-17T00:00:00.000Z", :chikou_span=>184.82, :kijun_sen=>173.83499999999998, :senkou_span_a=>180.73250000000002, :senkou_span_b=>190.19, :tenkan_sen=>167.64999999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :chikou_span=>178.58, :kijun_sen=>174.135, :senkou_span_a=>180.739875, :senkou_span_b=>191.95499999999998, :tenkan_sen=>168.925}, + {:date_time=>"2018-12-13T00:00:00.000Z", :chikou_span=>179.55, :kijun_sen=>174.135, :senkou_span_a=>179.727375, :senkou_span_b=>196.31, :tenkan_sen=>169.785}, + {:date_time=>"2018-12-12T00:00:00.000Z", :chikou_span=>180.94, :kijun_sen=>174.135, :senkou_span_a=>179.194875, :senkou_span_b=>196.31, :tenkan_sen=>167.625}, + {:date_time=>"2018-12-11T00:00:00.000Z", :chikou_span=>174.24, :kijun_sen=>174.135, :senkou_span_a=>178.57375000000002, :senkou_span_b=>196.31, :tenkan_sen=>168.91000000000003}, + {:date_time=>"2018-12-10T00:00:00.000Z", :chikou_span=>174.62, :kijun_sen=>174.135, :senkou_span_a=>180.16, :senkou_span_b=>196.31, :tenkan_sen=>169.055}, + {:date_time=>"2018-12-07T00:00:00.000Z", :chikou_span=>172.29, :kijun_sen=>176.62, :senkou_span_a=>182.92000000000002, :senkou_span_b=>197.23000000000002, :tenkan_sen=>175.34495}, + {:date_time=>"2018-12-06T00:00:00.000Z", :chikou_span=>176.78, :kijun_sen=>177.6, :senkou_span_a=>187.95999999999998, :senkou_span_b=>198.935, :tenkan_sen=>177.68}, + {:date_time=>"2018-12-04T00:00:00.000Z", :chikou_span=>176.98, :kijun_sen=>177.6, :senkou_span_a=>189.027375, :senkou_span_b=>199.87, :tenkan_sen=>180.60500000000002}, + {:date_time=>"2018-12-03T00:00:00.000Z", :chikou_span=>185.86, :kijun_sen=>180.48, :senkou_span_a=>193.76737500000002, :senkou_span_b=>204.61, :tenkan_sen=>180.985}, + {:date_time=>"2018-11-30T00:00:00.000Z", :chikou_span=>193.53, :kijun_sen=>182.61475000000002, :senkou_span_a=>194.237375, :senkou_span_b=>205.07999999999998, :tenkan_sen=>178.865}, + {:date_time=>"2018-11-29T00:00:00.000Z", :chikou_span=>191.41, :kijun_sen=>182.61475000000002, :senkou_span_a=>195.6725, :senkou_span_b=>205.07999999999998, :tenkan_sen=>176.84}, + {:date_time=>"2018-11-28T00:00:00.000Z", :chikou_span=>186.8, :kijun_sen=>182.61475000000002, :senkou_span_a=>198.51749999999998, :senkou_span_b=>205.07999999999998, :tenkan_sen=>175.77499999999998}, + {:date_time=>"2018-11-27T00:00:00.000Z", :chikou_span=>192.23, :kijun_sen=>183.72, :senkou_span_a=>202.81755, :senkou_span_b=>207.84005, :tenkan_sen=>173.4275}, + {:date_time=>"2018-11-26T00:00:00.000Z", :chikou_span=>194.17, :kijun_sen=>185.055, :senkou_span_a=>205.015, :senkou_span_b=>209.01, :tenkan_sen=>175.265}, + {:date_time=>"2018-11-23T00:00:00.000Z", :chikou_span=>204.47, :kijun_sen=>189.055, :senkou_span_a=>208.225, :senkou_span_b=>211.2, :tenkan_sen=>176.785}, + {:date_time=>"2018-11-21T00:00:00.000Z", :chikou_span=>208.49, :kijun_sen=>192.815, :senkou_span_a=>208.08499999999998, :senkou_span_b=>211.2, :tenkan_sen=>183.105}, + {:date_time=>"2018-11-20T00:00:00.000Z", :chikou_span=>209.95, :kijun_sen=>192.815, :senkou_span_a=>207.19, :senkou_span_b=>211.2, :tenkan_sen=>185.23975000000002}, + {:date_time=>"2018-11-19T00:00:00.000Z", :chikou_span=>203.77, :kijun_sen=>197.555, :senkou_span_a=>208.555, :senkou_span_b=>212.26, :tenkan_sen=>189.97975000000002}, + {:date_time=>"2018-11-16T00:00:00.000Z", :chikou_span=>201.59, :kijun_sen=>198.025, :senkou_span_a=>210.7325, :senkou_span_b=>212.72, :tenkan_sen=>190.44975} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/kc_spec.rb b/spec/technical_analysis/indicators/kc_spec.rb index 6105590..872e612 100644 --- a/spec/technical_analysis/indicators/kc_spec.rb +++ b/spec/technical_analysis/indicators/kc_spec.rb @@ -9,65 +9,66 @@ describe 'Keltner Channel' do it 'Calculates KC (10 day)' do output = indicator.calculate(input_data, period: 10) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:lower_band=>146.74034, :middle_band=>151.57433, :upper_band=>156.40832}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667}}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495}}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005}}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=> {:lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667}}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=> {:lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004}}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=> {:lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333}}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=> {:lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664}}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=> {:lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667}} + {:date_time=>"2019-01-09T00:00:00.000Z", :lower_band=>147.1630066666667, :middle_band=>151.9909966666667, :upper_band=>156.8189866666667}, + {:date_time=>"2019-01-08T00:00:00.000Z", :lower_band=>146.74034, :middle_band=>151.57433, :upper_band=>156.40832}, + {:date_time=>"2019-01-07T00:00:00.000Z", :lower_band=>146.46500666666665, :middle_band=>151.82199666666665, :upper_band=>157.17898666666665}, + {:date_time=>"2019-01-04T00:00:00.000Z", :lower_band=>147.12967333333333, :middle_band=>152.87466333333333, :upper_band=>158.61965333333333}, + {:date_time=>"2019-01-03T00:00:00.000Z", :lower_band=>148.32933333333335, :middle_band=>154.43533333333335, :upper_band=>160.54133333333334}, + {:date_time=>"2019-01-02T00:00:00.000Z", :lower_band=>150.65666666666667, :middle_band=>156.70466666666667, :upper_band=>162.75266666666667}, + {:date_time=>"2018-12-31T00:00:00.000Z", :lower_band=>151.35733333333334, :middle_band=>157.50533333333334, :upper_band=>163.65333333333334}, + {:date_time=>"2018-12-28T00:00:00.000Z", :lower_band=>152.14066666666668, :middle_band=>158.38066666666668, :upper_band=>164.6206666666667}, + {:date_time=>"2018-12-27T00:00:00.000Z", :lower_band=>153.69466666666665, :middle_band=>159.83966666666666, :upper_band=>165.98466666666667}, + {:date_time=>"2018-12-26T00:00:00.000Z", :lower_band=>155.643, :middle_band=>161.408, :upper_band=>167.17299999999997}, + {:date_time=>"2018-12-24T00:00:00.000Z", :lower_band=>157.75833333333333, :middle_band=>162.9513333333333, :upper_band=>168.1443333333333}, + {:date_time=>"2018-12-21T00:00:00.000Z", :lower_band=>159.51333333333332, :middle_band=>164.8863333333333, :upper_band=>170.2593333333333}, + {:date_time=>"2018-12-20T00:00:00.000Z", :lower_band=>161.50599999999997, :middle_band=>166.64499999999998, :upper_band=>171.784}, + {:date_time=>"2018-12-19T00:00:00.000Z", :lower_band=>163.27366666666666, :middle_band=>168.16766666666666, :upper_band=>173.06166666666667}, + {:date_time=>"2018-12-18T00:00:00.000Z", :lower_band=>165.09500666666668, :middle_band=>169.76499666666666, :upper_band=>174.43498666666665}, + {:date_time=>"2018-12-17T00:00:00.000Z", :lower_band=>166.80200666666667, :middle_band=>171.53099666666668, :upper_band=>176.2599866666667}, + {:date_time=>"2018-12-14T00:00:00.000Z", :lower_band=>168.39800666666667, :middle_band=>172.89499666666666, :upper_band=>177.39198666666664}, + {:date_time=>"2018-12-13T00:00:00.000Z", :lower_band=>169.60834, :middle_band=>174.23533, :upper_band=>178.86232}, + {:date_time=>"2018-12-12T00:00:00.000Z", :lower_band=>170.07734, :middle_band=>175.03833, :upper_band=>179.99932}, + {:date_time=>"2018-12-11T00:00:00.000Z", :lower_band=>170.30667333333332, :middle_band=>175.36666333333332, :upper_band=>180.42665333333332}, + {:date_time=>"2018-12-10T00:00:00.000Z", :lower_band=>170.73033999999998, :middle_band=>175.78033, :upper_band=>180.83032}, + {:date_time=>"2018-12-07T00:00:00.000Z", :lower_band=>171.55567333333335, :middle_band=>176.37916333333334, :upper_band=>181.20265333333333}, + {:date_time=>"2018-12-06T00:00:00.000Z", :lower_band=>172.54667333333333, :middle_band=>177.12316333333334, :upper_band=>181.69965333333334}, + {:date_time=>"2018-12-04T00:00:00.000Z", :lower_band=>172.85467333333332, :middle_band=>177.59116333333333, :upper_band=>182.32765333333333}, + {:date_time=>"2018-12-03T00:00:00.000Z", :lower_band=>173.76899999999998, :middle_band=>178.4645, :upper_band=>183.16}, + {:date_time=>"2018-11-30T00:00:00.000Z", :lower_band=>174.4907, :middle_band=>179.36415, :upper_band=>184.2376}, + {:date_time=>"2018-11-29T00:00:00.000Z", :lower_band=>175.45836666666665, :middle_band=>180.50881666666666, :upper_band=>185.55926666666667}, + {:date_time=>"2018-11-28T00:00:00.000Z", :lower_band=>176.01870000000002, :middle_band=>181.41415, :upper_band=>186.8096}, + {:date_time=>"2018-11-27T00:00:00.000Z", :lower_band=>177.53838, :middle_band=>182.87081999999998, :upper_band=>188.20325999999997}, + {:date_time=>"2018-11-26T00:00:00.000Z", :lower_band=>179.58538000000001, :middle_band=>185.13482000000002, :upper_band=>190.68426000000002}, + {:date_time=>"2018-11-23T00:00:00.000Z", :lower_band=>182.7750466666667, :middle_band=>188.23148666666668, :upper_band=>193.68792666666667}, + {:date_time=>"2018-11-21T00:00:00.000Z", :lower_band=>186.36671333333337, :middle_band=>191.71065333333337, :upper_band=>197.05459333333337}, + {:date_time=>"2018-11-20T00:00:00.000Z", :lower_band=>189.16371333333333, :middle_band=>194.72865333333334, :upper_band=>200.29359333333335}, + {:date_time=>"2018-11-19T00:00:00.000Z", :lower_band=>191.99738, :middle_band=>197.26932, :upper_band=>202.54126}, + {:date_time=>"2018-11-16T00:00:00.000Z", :lower_band=>193.36638000000002, :middle_band=>198.68932, :upper_band=>204.01226}, + {:date_time=>"2018-11-15T00:00:00.000Z", :lower_band=>194.71534666666665, :middle_band=>200.30933666666664, :upper_band=>205.90332666666663}, + {:date_time=>"2018-11-14T00:00:00.000Z", :lower_band=>197.70434666666668, :middle_band=>203.34633666666667, :upper_band=>208.98832666666667}, + {:date_time=>"2018-11-13T00:00:00.000Z", :lower_band=>201.13368, :middle_band=>206.30367, :upper_band=>211.47366000000002}, + {:date_time=>"2018-11-12T00:00:00.000Z", :lower_band=>203.012, :middle_band=>208.2, :upper_band=>213.38799999999998}, + {:date_time=>"2018-11-09T00:00:00.000Z", :lower_band=>203.93166666666667, :middle_band=>209.87366666666668, :upper_band=>215.8156666666667}, + {:date_time=>"2018-11-08T00:00:00.000Z", :lower_band=>204.77, :middle_band=>211.08800000000002, :upper_band=>217.40600000000003}, + {:date_time=>"2018-11-07T00:00:00.000Z", :lower_band=>205.72966666666667, :middle_band=>212.17366666666666, :upper_band=>218.61766666666665}, + {:date_time=>"2018-11-06T00:00:00.000Z", :lower_band=>206.34433333333334, :middle_band=>213.16433333333333, :upper_band=>219.98433333333332}, + {:date_time=>"2018-11-05T00:00:00.000Z", :lower_band=>207.47566666666665, :middle_band=>214.84766666666664, :upper_band=>222.21966666666663}, + {:date_time=>"2018-11-02T00:00:00.000Z", :lower_band=>209.61566666666667, :middle_band=>216.80766666666668, :upper_band=>223.99966666666668}, + {:date_time=>"2018-11-01T00:00:00.000Z", :lower_band=>211.10266666666666, :middle_band=>217.85566666666668, :upper_band=>224.6086666666667}, + {:date_time=>"2018-10-31T00:00:00.000Z", :lower_band=>210.5626666666667, :middle_band=>217.4346666666667, :upper_band=>224.30666666666667}, + {:date_time=>"2018-10-30T00:00:00.000Z", :lower_band=>210.85700000000003, :middle_band=>217.67600000000002, :upper_band=>224.495}, + {:date_time=>"2018-10-29T00:00:00.000Z", :lower_band=>211.63036000000005, :middle_band=>218.48109000000005, :upper_band=>225.33182000000005}, + {:date_time=>"2018-10-26T00:00:00.000Z", :lower_band=>213.14902666666669, :middle_band=>219.0957566666667, :upper_band=>225.0424866666667}, + {:date_time=>"2018-10-25T00:00:00.000Z", :lower_band=>213.71936000000002, :middle_band=>219.51809000000003, :upper_band=>225.31682000000004}, + {:date_time=>"2018-10-24T00:00:00.000Z", :lower_band=>213.0756933333333, :middle_band=>219.1294233333333, :upper_band=>225.1831533333333}, + {:date_time=>"2018-10-23T00:00:00.000Z", :lower_band=>213.17802666666663, :middle_band=>219.29275666666663, :upper_band=>225.40748666666664}, + {:date_time=>"2018-10-22T00:00:00.000Z", :lower_band=>214.05418666666668, :middle_band=>219.8162966666667, :upper_band=>225.5784066666667} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 2a42d09da83b14933b2946a7940276d39a42820e Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 14 Feb 2019 12:21:40 -0500 Subject: [PATCH 37/84] Add IndicatorValue - kst - macd - mfi - mi - nvi - obv - obv_mean - rsi - sma - sr - trix - tsi - uo - vi - vpt - wr --- lib/technical_analysis/indicators/kst.rb | 34 +++-- lib/technical_analysis/indicators/macd.rb | 70 ++++++---- lib/technical_analysis/indicators/mfi.rb | 33 +++-- lib/technical_analysis/indicators/mi.rb | 33 +++-- lib/technical_analysis/indicators/nvi.rb | 35 +++-- lib/technical_analysis/indicators/obv.rb | 33 +++-- lib/technical_analysis/indicators/obv_mean.rb | 33 +++-- lib/technical_analysis/indicators/rsi.rb | 33 +++-- lib/technical_analysis/indicators/sma.rb | 33 +++-- lib/technical_analysis/indicators/sr.rb | 57 ++++---- lib/technical_analysis/indicators/trix.rb | 33 +++-- lib/technical_analysis/indicators/tsi.rb | 36 +++-- lib/technical_analysis/indicators/uo.rb | 33 +++-- lib/technical_analysis/indicators/vi.rb | 57 ++++---- lib/technical_analysis/indicators/vpt.rb | 33 +++-- lib/technical_analysis/indicators/wr.rb | 33 +++-- .../indicators/indicator_spec.rb | 121 ++++++++-------- .../technical_analysis/indicators/kst_spec.rb | 45 +++--- .../indicators/macd_spec.rb | 63 ++++----- .../technical_analysis/indicators/mfi_spec.rb | 101 +++++++------- spec/technical_analysis/indicators/mi_spec.rb | 49 +++---- .../technical_analysis/indicators/nvi_spec.rb | 129 +++++++++--------- .../indicators/obv_mean_spec.rb | 109 +++++++-------- .../technical_analysis/indicators/obv_spec.rb | 129 +++++++++--------- .../technical_analysis/indicators/rsi_spec.rb | 101 +++++++------- .../technical_analysis/indicators/sma_spec.rb | 121 ++++++++-------- spec/technical_analysis/indicators/sr_spec.rb | 99 +++++++------- .../indicators/trix_spec.rb | 43 +++--- .../technical_analysis/indicators/tsi_spec.rb | 55 ++++---- spec/technical_analysis/indicators/uo_spec.rb | 73 +++++----- spec/technical_analysis/indicators/vi_spec.rb | 101 +++++++------- .../technical_analysis/indicators/vpt_spec.rb | 127 ++++++++--------- spec/technical_analysis/indicators/wr_spec.rb | 103 +++++++------- 33 files changed, 1213 insertions(+), 975 deletions(-) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 245cbd6..0e816ee 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Know Sure Thing class Kst < Indicator # Returns the symbol of the technical indicator @@ -55,14 +56,7 @@ def self.min_data_size(roc4: 30, sma4: 15, **params) # @param sma4 [Integer] The given period to calculate the SMA of the rate-of-change for RCMA4 # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -140.9140022298261}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -148.9261153101682}, - # ] + # @return [Array] An array of KstValue instances def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value) roc1 = roc1.to_i roc2 = roc2.to_i @@ -90,7 +84,8 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: kst = (1 * rcma1) + (2 * rcma2) + (3 * rcma3) + (4 * rcma4) - output << { date_time: date_time, value: kst } + output << KstValue.new(date_time: date_time, kst: kst) + index += 1 end @@ -112,4 +107,25 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: end end + + # The value class to be returned by calculations + class KstValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the kst calculation value + attr_accessor :kst + + def initialize(date_time: nil, kst: nil) + @date_time = date_time + @kst = kst + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, kst: @kst } + end + + end end diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 06b5194..ab4ccdd 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Moving Average Convergence Divergence class Macd < Indicator # Returns the symbol of the technical indicator @@ -50,28 +51,7 @@ def self.min_data_size(slow_period: 26, signal_period: 9, **params) # @param signal_period [Integer] The given period to calculate the signal line for MACD # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :macd_histogram => 0.8762597178840466, - # :macd_line => -8.126908458242355, - # :signal_line => -9.003168176126401 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :macd_histogram => 0.4770591535283888, - # :macd_line => -8.745173952069024, - # :signal_line => -9.222233105597413 - # } - # } - # ] + # @return [Array] An array of MacdValue instances def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :value) fast_period = fast_period.to_i slow_period = slow_period.to_i @@ -107,14 +87,12 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri signal = StockCalculation.ema(macd, macd_values, signal_period, prev_signal) prev_signal = signal - output << { + output << MacdValue.new( date_time: v[:date_time], - value: { - macd_line: macd, - signal_line: signal, - macd_histogram: macd - signal, - } - } + macd_line: macd, + signal_line: signal, + macd_histogram: macd - signal, + ) macd_values.shift end @@ -128,4 +106,38 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri end end + + # The value class to be returned by calculations + class MacdValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the macd_line calculation value + attr_accessor :macd_line + + # @return [Float] the macd_histogram calculation value + attr_accessor :macd_histogram + + # @return [Float] the signal_line calculation value + attr_accessor :signal_line + + def initialize(date_time: nil, macd_line: nil, macd_histogram: nil, signal_line: nil) + @date_time = date_time + @macd_line = macd_line + @macd_histogram = macd_histogram + @signal_line = signal_line + end + + # @return [Hash] the attributes as a hash + def to_hash + { + date_time: @date_time, + macd_line: @macd_line, + macd_histogram: @macd_histogram, + signal_line: @signal_line + } + end + + end end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index fe86c6b..de392b7 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Monoey Flow Index class Mfi < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(period: 14) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # @param period [Integer] The given period to calculate the MFI # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 50.72343663578981}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 50.1757147722236}, - # ] + # @return [Array] An array of MfiValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) @@ -88,7 +82,7 @@ def self.calculate(data, period: 14) money_flow_ratio = (positive_period_flows / negative_period_flows) mfi = (100.00 - (100.00 / (1.0 + money_flow_ratio))) - output << { date_time: v[:date_time], value: mfi } + output << MfiValue.new(date_time: v[:date_time], mfi: mfi) raw_money_flows.shift end @@ -100,4 +94,25 @@ def self.calculate(data, period: 14) end end + + # The value class to be returned by calculations + class MfiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the mfi calculation value + attr_accessor :mfi + + def initialize(date_time: nil, mfi: nil) + @date_time = date_time + @mfi = mfi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, mfi: @mfi } + end + + end end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 8938212..003c3b1 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Mass Index class Mi < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(ema_period: 9, sum_period: 25) # @param ema_period [Integer] The given period to calculate the EMA and EMA of EMA # @param sum_period [Integer] The given period to calculate the sum of EMA ratios # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 24.77520633216394}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 24.80084030980544}, - # ] + # @return [Array] An array of MiValue instances def self.calculate(data, ema_period: 9, sum_period: 25) ema_period = ema_period.to_i sum_period = sum_period.to_i @@ -85,7 +79,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) ratio_of_emas << (single_ema / double_ema) if ratio_of_emas.size == sum_period - output << { date_time: v[:date_time], value: ratio_of_emas.sum } + output << MiValue.new(date_time: v[:date_time], mi: ratio_of_emas.sum) double_emas.shift ratio_of_emas.shift @@ -102,4 +96,25 @@ def self.calculate(data, ema_period: 9, sum_period: 25) end end + + # The value class to be returned by calculations + class MiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the mi calculation value + attr_accessor :mi + + def initialize(date_time: nil, mi: nil) + @date_time = date_time + @mi = mi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, mi: @mi } + end + + end end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index 438ac98..b3cb8ac 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Negative Volume Index class Nvi < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 1002.8410612825647}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 1002.8410612825647}, - # ] + # @return [Array] An array of NviValue instances def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) @@ -65,7 +59,7 @@ def self.calculate(data) output = [] prev_price = data.shift - output << { date_time: prev_price[:date_time], value: nvi_cumulative } # Start with default of 1_000 + output << NviValue.new(date_time: prev_price[:date_time], nvi: nvi_cumulative) # Start with default of 1_000 data.each do |v| volume_change = ((v[:volume] - prev_price[:volume]) / prev_price[:volume]) @@ -75,7 +69,7 @@ def self.calculate(data) nvi_cumulative += price_change end - output << { date_time: v[:date_time], value: nvi_cumulative } + output << NviValue.new(date_time: v[:date_time], nvi: nvi_cumulative) prev_price = v end @@ -83,4 +77,25 @@ def self.calculate(data) end end + + # The value class to be returned by calculations + class NviValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the nvi calculation value + attr_accessor :nvi + + def initialize(date_time: nil, nvi: nil) + @date_time = date_time + @nvi = nvi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, nvi: @nvi } + end + + end end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 833e7a0..c63a7e1 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # On-balance Volume class Obv < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -591085010}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -636119380}, - # ] + # @return [Array] An array of ObvValue instances def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) @@ -75,7 +69,7 @@ def self.calculate(data) current_obv -= volume if close < prior_close end - output << { date_time: v[:date_time], value: current_obv } + output << ObvValue.new(date_time: v[:date_time], obv: current_obv) prior_volume = volume prior_close = close @@ -85,4 +79,25 @@ def self.calculate(data) end end + + # The value class to be returned by calculations + class ObvValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the obv calculation value + attr_accessor :obv + + def initialize(date_time: nil, obv: nil) + @date_time = date_time + @obv = obv + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, obv: @obv } + end + + end end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 5dac9b7..8286b14 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # On-balance Volume Mean class ObvMean < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(period: 10) # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # @param period [Integer] The given period to calculate the OBV mean # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -642606913.0}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -654187384.0}, - # ] + # @return [Array] An array of ObvMeanValue instances def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :close, :volume) @@ -82,7 +76,7 @@ def self.calculate(data, period: 10) prior_close = close if obvs.size == period - output << { date_time: v[:date_time], value: obvs.average } + output << ObvMeanValue.new(date_time: v[:date_time], obv_mean: obvs.average) obvs.shift end end @@ -91,4 +85,25 @@ def self.calculate(data, period: 10) end end + + # The value class to be returned by calculations + class ObvMeanValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the obv_mean calculation value + attr_accessor :obv_mean + + def initialize(date_time: nil, obv_mean: nil) + @date_time = date_time + @obv_mean = obv_mean + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, obv_mean: @obv_mean } + end + + end end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index cc554f4..c62b600 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Relative Strength Index class Rsi < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(period: 14, **params) # @param period [Integer] The given period to calculate the RSI # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 41.01572095202713}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 38.100858593859655}, - # ] + # @return [Array] An array of RsiValue instances def self.calculate(data, period: 14, price_key: :value) period = period.to_i price_key = price_key.to_sym @@ -101,7 +95,7 @@ def self.calculate(data, period: 14, price_key: :value) rsi = (100.00 - (100.00 / (1.00 + rs))) end - output << { date_time: v[:date_time], value: rsi } + output << RsiValue.new(date_time: v[:date_time], rsi: rsi) prev_avg = { gain: avg_gain, loss: avg_loss } price_changes.shift @@ -114,4 +108,25 @@ def self.calculate(data, period: 14, price_key: :value) end end + + # The value class to be returned by calculations + class RsiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the rsi calculation value + attr_accessor :rsi + + def initialize(date_time: nil, rsi: nil) + @date_time = date_time + @rsi = rsi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, rsi: @rsi } + end + + end end diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 5e39994..342ead9 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Simple Moving Average class Sma < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(period: 30, **params) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 148.488}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 149.41}, - # ] + # @return [Array] An array of SmaValue instances def self.calculate(data, period: 30, price_key: :value) period = period.to_i price_key = price_key.to_sym @@ -70,7 +64,7 @@ def self.calculate(data, period: 30, price_key: :value) data.each do |v| period_values << v[price_key] if period_values.size == period - output << { date_time: v[:date_time], value: period_values.average } + output << SmaValue.new(date_time: v[:date_time], sma: period_values.average) period_values.shift end end @@ -79,4 +73,25 @@ def self.calculate(data, period: 30, price_key: :value) end end + + # The value class to be returned by calculations + class SmaValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the sma calculation value + attr_accessor :sma + + def initialize(date_time: nil, sma: nil) + @date_time = date_time + @sma = sma + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, sma: @sma } + end + + end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index e697d86..6384439 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Stochastic Oscillator class Sr < Indicator # Returns the symbol of the technical indicator @@ -48,26 +49,7 @@ def self.min_data_size(period: 14, signal_period: 3) # @param period [Integer] The given period to calculate the SR # @param signal_period [Integer] The given period to calculate the SMA as a signal line for SR # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :sr => 44.44007858546172, - # :sr_signal => 33.739408752366685 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :sr => 34.27340383862123, - # :sr_signal => 26.631612985573174 - # } - # }, - # ] + # @return [Array] An array of SrValue instances def self.calculate(data, period: 14, signal_period: 3) period = period.to_i signal_period = signal_period.to_i @@ -94,13 +76,11 @@ def self.calculate(data, period: 14, signal_period: 3) if sr_values.size == signal_period signal = sr_values.average - output << { + output << SrValue.new( date_time: v[:date_time], - value: { - sr: sr, - sr_signal: signal - } - } + sr: sr, + sr_signal: signal + ) sr_values.shift end @@ -113,4 +93,29 @@ def self.calculate(data, period: 14, signal_period: 3) end end + + # The value class to be returned by calculations + class SrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the sr calculation value + attr_accessor :sr + + # @return [Float] the sr_signal calculation value + attr_accessor :sr_signal + + def initialize(date_time: nil, sr: nil, sr_signal: nil) + @date_time = date_time + @sr = sr + @sr_signal = sr_signal + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, sr: @sr, sr_signal: @sr_signal } + end + + end end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index d4a20a7..5ca104f 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Triple Exponential Average class Trix < Indicator # Returns the symbol of the technical indicator @@ -48,14 +49,7 @@ def self.min_data_size(period: 15, **params) # @param period [Integer] The given period to calculate the EMA for Trix # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -0.007522826289174942}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -0.007639218329257057}, - # ] + # @return [Array] An array of TrixValue instances def self.calculate(data, period: 15, price_key: :value) period = period.to_i price_key = price_key.to_sym @@ -89,7 +83,7 @@ def self.calculate(data, period: 15, price_key: :value) if ema3.size == 2 prev_ema3, current_ema3 = ema3 trix = ((current_ema3 - prev_ema3) / prev_ema3) - output << { date_time: v[:date_time], value: trix } + output << TrixValue.new(date_time: v[:date_time], trix: trix) ema3.shift end @@ -108,4 +102,25 @@ def self.calculate(data, period: 15, price_key: :value) end end + + # The value class to be returned by calculations + class TrixValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the trix calculation value + attr_accessor :trix + + def initialize(date_time: nil, trix: nil) + @date_time = date_time + @trix = trix + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, trix: @trix } + end + + end end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index ae56267..54eeee6 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # True Strength Index class Tsi < Indicator # Returns the symbol of the technical indicator @@ -49,14 +50,7 @@ def self.min_data_size(low_period: 13, high_period: 25, **params) # @param low_period [Integer] The given low period to calculate the EMA # @param price_key [Symbol] The hash key for the price data. Default :value # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -28.91017661103889}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -30.97413963420104}, - # ] + # @return [Array] An array of TsiValue instances def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) low_period = low_period.to_i high_period = high_period.to_i @@ -88,7 +82,10 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) low_ema = process_ema(high_emas.last, high_emas, low_multiplier, low_period, low_emas) low_emas << low_ema - output << { date_time: v[:date_time], value: ((100 * (low_ema[:value] / low_ema[:abs_value]))) } + output << TsiValue.new( + date_time: v[:date_time], + tsi: ((100 * (low_ema[:value] / low_ema[:abs_value]))) + ) low_emas.shift if low_emas.size > 1 # Only need to retain the last low_ema high_emas.shift @@ -117,4 +114,25 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) end end + + # The value class to be returned by calculations + class TsiValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the tsi calculation value + attr_accessor :tsi + + def initialize(date_time: nil, tsi: nil) + @date_time = date_time + @tsi = tsi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, tsi: @tsi } + end + + end end diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index e8f337c..0b95255 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Ultimate Oscillator class Uo < Indicator # Returns the symbol of the technical indicator @@ -52,14 +53,7 @@ def self.min_data_size(long_period: 28, **params) # @param medium_weight [Float] Weight of medium Buying Pressure average for UO # @param long_weight [Float] Weight of long Buying Pressure average for UO # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => 47.28872762629681}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => 44.828908983561035}, - # ] + # @return [Array] An array of UoValue instances def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) short_period = short_period.to_i medium_period = medium_period.to_i @@ -92,7 +86,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh long_average = calculate_average(long_period, period_values) uo = 100 * (((short_weight * short_average) + (medium_weight * medium_average) + (long_weight * long_average)) / (sum_of_weights)) - output << { date_time: v[:date_time], value: uo } + output << UoValue.new(date_time: v[:date_time], uo: uo) period_values.shift end @@ -111,4 +105,25 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh end end + + # The value class to be returned by calculations + class UoValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the uo calculation value + attr_accessor :uo + + def initialize(date_time: nil, uo: nil) + @date_time = date_time + @uo = uo + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, uo: @uo } + end + + end end diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 99ad6e4..60fa607 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Vortex Indicator class Vi < Indicator # Returns the symbol of the technical indicator @@ -47,26 +48,7 @@ def self.min_data_size(period: 14) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given period to calculate the VI # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # { - # :date_time => "2019-01-09T00:00:00.000Z", - # :value => { - # :negative_vi => 0.9777149447928525, - # :positive_vi => 0.8609629970246735 - # } - # }, - # { - # :date_time => "2019-01-08T00:00:00.000Z", - # :value => { - # :negative_vi => 1.0113586362578701, - # :positive_vi => 0.8600571901821686 - # } - # }, - # ] + # @return [Array] An array of ViValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -90,13 +72,11 @@ def self.calculate(data, period: 14) neg_vm_period = period_values.map { |pv| pv[:neg_vm] }.sum tr_period = period_values.map { |pv| pv[:tr] }.sum - output << { + output << ViValue.new( date_time: v[:date_time], - value: { - positive_vi: (pos_vm_period / tr_period), - negative_vi: (neg_vm_period / tr_period), - } - } + positive_vi: (pos_vm_period / tr_period), + negative_vi: (neg_vm_period / tr_period), + ) period_values.shift end @@ -108,4 +88,29 @@ def self.calculate(data, period: 14) end end + + # The value class to be returned by calculations + class ViValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the positive Vortex Indicator value + attr_accessor :positive_vi + + # @return [Float] the negative Vortex Indicator value + attr_accessor :negative_vi + + def initialize(date_time: nil, positive_vi: nil, negative_vi: nil) + @date_time = date_time + @positive_vi = positive_vi + @negative_vi = negative_vi + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, positive_vi: @positive_vi, negative_vi: @negative_vi } + end + + end end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index d00e6e2..cee874e 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Volume-price Trend class Vpt < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(**params) # # @param data [Array] Array of hashes with keys (:date_time, :close, :volume) # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -27383899.78109331}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -28148662.548589166}, - # ] + # @return [Array] An array of VptValue instances def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) @@ -67,7 +61,7 @@ def self.calculate(data) data.each do |v| pvt = prev_pvt + (((v[:close] - prev_price[:close]) / prev_price[:close]) * v[:volume]) - output << { date_time: v[:date_time], value: pvt } + output << VptValue.new(date_time: v[:date_time], vpt: pvt) prev_price = v prev_pvt = pvt end @@ -76,4 +70,25 @@ def self.calculate(data) end end + + # The value class to be returned by calculations + class VptValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the vpt calculation value + attr_accessor :vpt + + def initialize(date_time: nil, vpt: nil) + @date_time = date_time + @vpt = vpt + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, vpt: @vpt } + end + + end end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index fa7d1df..3c24fa9 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -1,4 +1,5 @@ module TechnicalAnalysis + # Williams %R class Wr < Indicator # Returns the symbol of the technical indicator @@ -47,14 +48,7 @@ def self.min_data_size(period: 14) # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) # @param period [Integer] The given look-back period to calculate the WR # - # @return [Array] - # - # An array of hashes with keys (:date_time, :value). Example output: - # - # [ - # {:date_time => "2019-01-09T00:00:00.000Z", :value => -55.55992141453828}, - # {:date_time => "2019-01-08T00:00:00.000Z", :value => -65.72659616137877}, - # ] + # @return [Array] An array of WrValue instances def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) @@ -74,7 +68,7 @@ def self.calculate(data, period: 14) wr = (highest_high - v[:close]) / (highest_high - lowest_low) * -100 - output << { date_time: v[:date_time], value: wr } + output << WrValue.new(date_time: v[:date_time], wr: wr) period_values.shift end @@ -84,4 +78,25 @@ def self.calculate(data, period: 14) end end + + # The value class to be returned by calculations + class WrValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the wr calculation value + attr_accessor :wr + + def initialize(date_time: nil, wr: nil) + @date_time = date_time + @wr = wr + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, wr: @wr } + end + + end end diff --git a/spec/technical_analysis/indicators/indicator_spec.rb b/spec/technical_analysis/indicators/indicator_spec.rb index c8a07bc..9fb8ef9 100644 --- a/spec/technical_analysis/indicators/indicator_spec.rb +++ b/spec/technical_analysis/indicators/indicator_spec.rb @@ -49,70 +49,71 @@ it 'Calculates technicals' do input_data = SpecHelper.get_test_data(:close) output = indicator.calculate('sma', input_data, :technicals, { period: 5, price_key: :close }) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>149.41}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43} + {:date_time=>"2019-01-09T00:00:00.000Z", :sma=>148.488}, + {:date_time=>"2019-01-08T00:00:00.000Z", :sma=>149.41}, + {:date_time=>"2019-01-07T00:00:00.000Z", :sma=>150.808}, + {:date_time=>"2019-01-04T00:00:00.000Z", :sma=>152.468}, + {:date_time=>"2019-01-03T00:00:00.000Z", :sma=>154.046}, + {:date_time=>"2019-01-02T00:00:00.000Z", :sma=>157.04199999999997}, + {:date_time=>"2018-12-31T00:00:00.000Z", :sma=>154.824}, + {:date_time=>"2018-12-28T00:00:00.000Z", :sma=>153.422}, + {:date_time=>"2018-12-27T00:00:00.000Z", :sma=>153.54199999999997}, + {:date_time=>"2018-12-26T00:00:00.000Z", :sma=>154.49}, + {:date_time=>"2018-12-24T00:00:00.000Z", :sma=>156.27}, + {:date_time=>"2018-12-21T00:00:00.000Z", :sma=>159.692}, + {:date_time=>"2018-12-20T00:00:00.000Z", :sma=>162.642}, + {:date_time=>"2018-12-19T00:00:00.000Z", :sma=>165.46599999999998}, + {:date_time=>"2018-12-18T00:00:00.000Z", :sma=>167.108}, + {:date_time=>"2018-12-17T00:00:00.000Z", :sma=>167.61999999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :sma=>168.752}, + {:date_time=>"2018-12-13T00:00:00.000Z", :sma=>169.35399999999998}, + {:date_time=>"2018-12-12T00:00:00.000Z", :sma=>170.108}, + {:date_time=>"2018-12-11T00:00:00.000Z", :sma=>171.626}, + {:date_time=>"2018-12-10T00:00:00.000Z", :sma=>174.864}, + {:date_time=>"2018-12-07T00:00:00.000Z", :sma=>176.66}, + {:date_time=>"2018-12-06T00:00:00.000Z", :sma=>178.872}, + {:date_time=>"2018-12-04T00:00:00.000Z", :sma=>180.11600000000004}, + {:date_time=>"2018-12-03T00:00:00.000Z", :sma=>179.62600000000003}, + {:date_time=>"2018-11-30T00:00:00.000Z", :sma=>177.58599999999998}, + {:date_time=>"2018-11-29T00:00:00.000Z", :sma=>176.32799999999997}, + {:date_time=>"2018-11-28T00:00:00.000Z", :sma=>175.77400000000003}, + {:date_time=>"2018-11-27T00:00:00.000Z", :sma=>174.982}, + {:date_time=>"2018-11-26T00:00:00.000Z", :sma=>177.30599999999998}, + {:date_time=>"2018-11-23T00:00:00.000Z", :sma=>181.088}, + {:date_time=>"2018-11-21T00:00:00.000Z", :sma=>184.91199999999998}, + {:date_time=>"2018-11-20T00:00:00.000Z", :sma=>186.916}, + {:date_time=>"2018-11-19T00:00:00.000Z", :sma=>189.96599999999998}, + {:date_time=>"2018-11-16T00:00:00.000Z", :sma=>191.628}, + {:date_time=>"2018-11-15T00:00:00.000Z", :sma=>193.816}, + {:date_time=>"2018-11-14T00:00:00.000Z", :sma=>197.23200000000003}, + {:date_time=>"2018-11-13T00:00:00.000Z", :sma=>201.862}, + {:date_time=>"2018-11-12T00:00:00.000Z", :sma=>204.17000000000002}, + {:date_time=>"2018-11-09T00:00:00.000Z", :sma=>205.654}, + {:date_time=>"2018-11-08T00:00:00.000Z", :sma=>206.256}, + {:date_time=>"2018-11-07T00:00:00.000Z", :sma=>209.002}, + {:date_time=>"2018-11-06T00:00:00.000Z", :sma=>210.78400000000002}, + {:date_time=>"2018-11-05T00:00:00.000Z", :sma=>212.69}, + {:date_time=>"2018-11-02T00:00:00.000Z", :sma=>214.82000000000002}, + {:date_time=>"2018-11-01T00:00:00.000Z", :sma=>216.584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :sma=>216.1}, + {:date_time=>"2018-10-30T00:00:00.000Z", :sma=>215.346}, + {:date_time=>"2018-10-29T00:00:00.000Z", :sma=>217.23200000000003}, + {:date_time=>"2018-10-26T00:00:00.000Z", :sma=>218.914}, + {:date_time=>"2018-10-25T00:00:00.000Z", :sma=>219.51600000000002}, + {:date_time=>"2018-10-24T00:00:00.000Z", :sma=>218.76}, + {:date_time=>"2018-10-23T00:00:00.000Z", :sma=>219.97999999999996}, + {:date_time=>"2018-10-22T00:00:00.000Z", :sma=>219.86400000000003}, + {:date_time=>"2018-10-19T00:00:00.000Z", :sma=>219.206}, + {:date_time=>"2018-10-18T00:00:00.000Z", :sma=>219.766}, + {:date_time=>"2018-10-17T00:00:00.000Z", :sma=>219.452}, + {:date_time=>"2018-10-16T00:00:00.000Z", :sma=>218.48600000000002}, + {:date_time=>"2018-10-15T00:00:00.000Z", :sma=>219.43} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end end end diff --git a/spec/technical_analysis/indicators/kst_spec.rb b/spec/technical_analysis/indicators/kst_spec.rb index 97a3478..b0c83c0 100644 --- a/spec/technical_analysis/indicators/kst_spec.rb +++ b/spec/technical_analysis/indicators/kst_spec.rb @@ -9,31 +9,32 @@ describe 'Know Sure Thing' do it 'Calculates KST' do output = indicator.calculate(input_data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-140.9140022298261}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-148.9261153101682}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-155.71040741442587}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-157.83675223915662}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-157.0260814891967}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-150.77021075475108}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-152.43337072156913}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-154.278039839607}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-152.69243922992774}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-151.25248412993977}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-150.769274028613}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-145.9029270207904}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-143.4025404878081}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-141.34365936138443}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-141.36803679622636}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-140.69442915235626}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-141.6235541026754}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-143.06704590371226}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-146.67417088368043}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-150.14198896419614} + {:date_time=>"2019-01-09T00:00:00.000Z", :kst=>-140.9140022298261}, + {:date_time=>"2019-01-08T00:00:00.000Z", :kst=>-148.9261153101682}, + {:date_time=>"2019-01-07T00:00:00.000Z", :kst=>-155.71040741442587}, + {:date_time=>"2019-01-04T00:00:00.000Z", :kst=>-157.83675223915662}, + {:date_time=>"2019-01-03T00:00:00.000Z", :kst=>-157.0260814891967}, + {:date_time=>"2019-01-02T00:00:00.000Z", :kst=>-150.77021075475108}, + {:date_time=>"2018-12-31T00:00:00.000Z", :kst=>-152.43337072156913}, + {:date_time=>"2018-12-28T00:00:00.000Z", :kst=>-154.278039839607}, + {:date_time=>"2018-12-27T00:00:00.000Z", :kst=>-152.69243922992774}, + {:date_time=>"2018-12-26T00:00:00.000Z", :kst=>-151.25248412993977}, + {:date_time=>"2018-12-24T00:00:00.000Z", :kst=>-150.769274028613}, + {:date_time=>"2018-12-21T00:00:00.000Z", :kst=>-145.9029270207904}, + {:date_time=>"2018-12-20T00:00:00.000Z", :kst=>-143.4025404878081}, + {:date_time=>"2018-12-19T00:00:00.000Z", :kst=>-141.34365936138443}, + {:date_time=>"2018-12-18T00:00:00.000Z", :kst=>-141.36803679622636}, + {:date_time=>"2018-12-17T00:00:00.000Z", :kst=>-140.69442915235626}, + {:date_time=>"2018-12-14T00:00:00.000Z", :kst=>-141.6235541026754}, + {:date_time=>"2018-12-13T00:00:00.000Z", :kst=>-143.06704590371226}, + {:date_time=>"2018-12-12T00:00:00.000Z", :kst=>-146.67417088368043}, + {:date_time=>"2018-12-11T00:00:00.000Z", :kst=>-150.14198896419614} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do @@ -58,7 +59,7 @@ end it 'Validates options' do - valid_options = { roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :value } + valid_options = { roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: 10, sma3: 10, sma4: 15, price_key: :kst } options_validated = indicator.validate_options(valid_options) expect(options_validated).to eq(true) end diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb index 93baed1..c41cc96 100644 --- a/spec/technical_analysis/indicators/macd_spec.rb +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -9,41 +9,42 @@ describe 'Moving Average Convergence Divergence' do it 'Calculates MACD (12, 26, 9)' do output = indicator.calculate(input_data, fast_period: 12, slow_period: 26, signal_period: 9, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:macd_histogram=>0.4770591535283888, :macd_line=>-8.745173952069024, :signal_line=>-9.222233105597413}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922}} + {:date_time=>"2019-01-09T00:00:00.000Z", :macd_histogram=>0.8762597178840466, :macd_line=>-8.126908458242355, :signal_line=>-9.003168176126401}, + {:date_time=>"2019-01-08T00:00:00.000Z", :macd_histogram=>0.4770591535283888, :macd_line=>-8.745173952069024, :signal_line=>-9.222233105597413}, + {:date_time=>"2019-01-07T00:00:00.000Z", :macd_histogram=>0.19504942363819744, :macd_line=>-9.146448470341312, :signal_line=>-9.34149789397951}, + {:date_time=>"2019-01-04T00:00:00.000Z", :macd_histogram=>0.15180609943062073, :macd_line=>-9.238454150458438, :signal_line=>-9.390260249889058}, + {:date_time=>"2019-01-03T00:00:00.000Z", :macd_histogram=>0.17310243476363496, :macd_line=>-9.255109339983079, :signal_line=>-9.428211774746714}, + {:date_time=>"2019-01-02T00:00:00.000Z", :macd_histogram=>0.9477761010428516, :macd_line=>-8.523711282394771, :signal_line=>-9.471487383437623}, + {:date_time=>"2018-12-31T00:00:00.000Z", :macd_histogram=>0.6406312657329245, :macd_line=>-9.06780014296541, :signal_line=>-9.708431408698335}, + {:date_time=>"2018-12-28T00:00:00.000Z", :macd_histogram=>0.25655639311731626, :macd_line=>-9.61203283201425, :signal_line=>-9.868589225131567}, + {:date_time=>"2018-12-27T00:00:00.000Z", :macd_histogram=>-0.0803864814327433, :macd_line=>-10.013114804843639, :signal_line=>-9.932728323410895}, + {:date_time=>"2018-12-26T00:00:00.000Z", :macd_histogram=>-0.45861878631368036, :macd_line=>-10.371250489366389, :signal_line=>-9.912631703052709}, + {:date_time=>"2018-12-24T00:00:00.000Z", :macd_histogram=>-0.9833848403830618, :macd_line=>-10.78136184685735, :signal_line=>-9.797977006474289}, + {:date_time=>"2018-12-21T00:00:00.000Z", :macd_histogram=>-0.5430624653584708, :macd_line=>-10.095193261736995, :signal_line=>-9.552130796378524}, + {:date_time=>"2018-12-20T00:00:00.000Z", :macd_histogram=>-0.053279185610067614, :macd_line=>-9.469644365648975, :signal_line=>-9.416365180038907}, + {:date_time=>"2018-12-19T00:00:00.000Z", :macd_histogram=>0.24847825431282367, :macd_line=>-9.154567129323567, :signal_line=>-9.40304538363639}, + {:date_time=>"2018-12-18T00:00:00.000Z", :macd_histogram=>0.4325264668638127, :macd_line=>-9.032638480350784, :signal_line=>-9.465164947214596}, + {:date_time=>"2018-12-17T00:00:00.000Z", :macd_histogram=>0.30024902798283826, :macd_line=>-9.273047535947711, :signal_line=>-9.57329656393055}, + {:date_time=>"2018-12-14T00:00:00.000Z", :macd_histogram=>0.420215327266785, :macd_line=>-9.228143493659474, :signal_line=>-9.648358820926259}, + {:date_time=>"2018-12-13T00:00:00.000Z", :macd_histogram=>0.5600105875119272, :macd_line=>-9.193402065231027, :signal_line=>-9.753412652742954}, + {:date_time=>"2018-12-12T00:00:00.000Z", :macd_histogram=>0.3211326876237397, :macd_line=>-9.572282611997196, :signal_line=>-9.893415299620935}, + {:date_time=>"2018-12-11T00:00:00.000Z", :macd_histogram=>0.24542334510443808, :macd_line=>-9.728275126422432, :signal_line=>-9.97369847152687}, + {:date_time=>"2018-12-10T00:00:00.000Z", :macd_histogram=>0.29703273753484893, :macd_line=>-9.738021570268131, :signal_line=>-10.03505430780298}, + {:date_time=>"2018-12-07T00:00:00.000Z", :macd_histogram=>0.40173122915939885, :macd_line=>-9.707581263027294, :signal_line=>-10.109312492186692}, + {:date_time=>"2018-12-06T00:00:00.000Z", :macd_histogram=>0.7952363015170398, :macd_line=>-9.414508997959501, :signal_line=>-10.209745299476541}, + {:date_time=>"2018-12-04T00:00:00.000Z", :macd_histogram=>0.8707231988258766, :macd_line=>-9.537831176029925, :signal_line=>-10.408554374855802}, + {:date_time=>"2018-12-03T00:00:00.000Z", :macd_histogram=>0.8691503265374259, :macd_line=>-9.757084848024846, :signal_line=>-10.626235174562272}, + {:date_time=>"2018-11-30T00:00:00.000Z", :macd_histogram=>0.12072991006954936, :macd_line=>-10.722792846127078, :signal_line=>-10.843522756196627}, + {:date_time=>"2018-11-29T00:00:00.000Z", :macd_histogram=>-0.29036883404714864, :macd_line=>-11.164074067761163, :signal_line=>-10.873705233714015}, + {:date_time=>"2018-11-28T00:00:00.000Z", :macd_histogram=>-0.8625734517317483, :macd_line=>-11.663686476933975, :signal_line=>-10.801113025202227}, + {:date_time=>"2018-11-27T00:00:00.000Z", :macd_histogram=>-1.6877775772534704, :macd_line=>-12.27324723952276, :signal_line=>-10.58546966226929}, + {:date_time=>"2018-11-26T00:00:00.000Z", :macd_histogram=>-2.0270413850598707, :macd_line=>-12.190566653015793, :signal_line=>-10.163525267955922} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/mfi_spec.rb b/spec/technical_analysis/indicators/mfi_spec.rb index 7fcc9df..073a9ca 100644 --- a/spec/technical_analysis/indicators/mfi_spec.rb +++ b/spec/technical_analysis/indicators/mfi_spec.rb @@ -9,60 +9,61 @@ describe 'Money Flow Index' do it 'Calculates MFI (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>50.72343663578981}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>50.1757147722236}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>44.40424662233335}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>37.81171947764313}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>36.12141791144509}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>44.40322811326429}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>50.84666407662511}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>43.66248537462054}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>37.56125308902594}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>30.54886108664553}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.795547568232564}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>29.111701049682864}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>31.23926122664477}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>39.506183778454634}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>47.447534147092476}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>48.23034273673764}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>47.94902504034211}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>49.219385053554596}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>43.77747404533765}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>35.65846689890073}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>28.368262151706787}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>36.043235982173}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>43.83608665179891}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>42.20999531156955}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>41.56028762200471}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>34.05798943239071}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>34.06816082393442}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>32.76065853310956}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>31.964707056845796}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>31.547361595662196}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.0162422598642}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>26.562703378271138}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>33.960148214906965}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>41.216526023725}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>41.22749344358184}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>35.21136683265594}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>28.384945303826555}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>34.34229761188338}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>34.42914208336833}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>34.82129345577579}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>39.93886476277229}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>40.83081970751587}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>35.50426811855657}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78216906343063}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>41.95906812943111}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>46.69168911629936}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>45.214622261116865}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>36.38768375444253}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>35.973926377719295} + {:date_time=>"2019-01-09T00:00:00.000Z", :mfi=>50.72343663578981}, + {:date_time=>"2019-01-08T00:00:00.000Z", :mfi=>50.1757147722236}, + {:date_time=>"2019-01-07T00:00:00.000Z", :mfi=>44.40424662233335}, + {:date_time=>"2019-01-04T00:00:00.000Z", :mfi=>37.81171947764313}, + {:date_time=>"2019-01-03T00:00:00.000Z", :mfi=>36.12141791144509}, + {:date_time=>"2019-01-02T00:00:00.000Z", :mfi=>44.40322811326429}, + {:date_time=>"2018-12-31T00:00:00.000Z", :mfi=>50.84666407662511}, + {:date_time=>"2018-12-28T00:00:00.000Z", :mfi=>43.66248537462054}, + {:date_time=>"2018-12-27T00:00:00.000Z", :mfi=>37.56125308902594}, + {:date_time=>"2018-12-26T00:00:00.000Z", :mfi=>30.54886108664553}, + {:date_time=>"2018-12-24T00:00:00.000Z", :mfi=>22.795547568232564}, + {:date_time=>"2018-12-21T00:00:00.000Z", :mfi=>29.111701049682864}, + {:date_time=>"2018-12-20T00:00:00.000Z", :mfi=>31.23926122664477}, + {:date_time=>"2018-12-19T00:00:00.000Z", :mfi=>39.506183778454634}, + {:date_time=>"2018-12-18T00:00:00.000Z", :mfi=>47.447534147092476}, + {:date_time=>"2018-12-17T00:00:00.000Z", :mfi=>48.23034273673764}, + {:date_time=>"2018-12-14T00:00:00.000Z", :mfi=>47.94902504034211}, + {:date_time=>"2018-12-13T00:00:00.000Z", :mfi=>49.219385053554596}, + {:date_time=>"2018-12-12T00:00:00.000Z", :mfi=>43.77747404533765}, + {:date_time=>"2018-12-11T00:00:00.000Z", :mfi=>35.65846689890073}, + {:date_time=>"2018-12-10T00:00:00.000Z", :mfi=>28.368262151706787}, + {:date_time=>"2018-12-07T00:00:00.000Z", :mfi=>36.043235982173}, + {:date_time=>"2018-12-06T00:00:00.000Z", :mfi=>43.83608665179891}, + {:date_time=>"2018-12-04T00:00:00.000Z", :mfi=>42.20999531156955}, + {:date_time=>"2018-12-03T00:00:00.000Z", :mfi=>41.56028762200471}, + {:date_time=>"2018-11-30T00:00:00.000Z", :mfi=>34.05798943239071}, + {:date_time=>"2018-11-29T00:00:00.000Z", :mfi=>34.06816082393442}, + {:date_time=>"2018-11-28T00:00:00.000Z", :mfi=>32.76065853310956}, + {:date_time=>"2018-11-27T00:00:00.000Z", :mfi=>31.964707056845796}, + {:date_time=>"2018-11-26T00:00:00.000Z", :mfi=>31.547361595662196}, + {:date_time=>"2018-11-23T00:00:00.000Z", :mfi=>30.0162422598642}, + {:date_time=>"2018-11-21T00:00:00.000Z", :mfi=>26.562703378271138}, + {:date_time=>"2018-11-20T00:00:00.000Z", :mfi=>33.960148214906965}, + {:date_time=>"2018-11-19T00:00:00.000Z", :mfi=>41.216526023725}, + {:date_time=>"2018-11-16T00:00:00.000Z", :mfi=>41.22749344358184}, + {:date_time=>"2018-11-15T00:00:00.000Z", :mfi=>35.21136683265594}, + {:date_time=>"2018-11-14T00:00:00.000Z", :mfi=>28.384945303826555}, + {:date_time=>"2018-11-13T00:00:00.000Z", :mfi=>34.34229761188338}, + {:date_time=>"2018-11-12T00:00:00.000Z", :mfi=>34.42914208336833}, + {:date_time=>"2018-11-09T00:00:00.000Z", :mfi=>34.82129345577579}, + {:date_time=>"2018-11-08T00:00:00.000Z", :mfi=>39.93886476277229}, + {:date_time=>"2018-11-07T00:00:00.000Z", :mfi=>40.83081970751587}, + {:date_time=>"2018-11-06T00:00:00.000Z", :mfi=>35.50426811855657}, + {:date_time=>"2018-11-05T00:00:00.000Z", :mfi=>34.78216906343063}, + {:date_time=>"2018-11-02T00:00:00.000Z", :mfi=>41.95906812943111}, + {:date_time=>"2018-11-01T00:00:00.000Z", :mfi=>46.69168911629936}, + {:date_time=>"2018-10-31T00:00:00.000Z", :mfi=>45.214622261116865}, + {:date_time=>"2018-10-30T00:00:00.000Z", :mfi=>36.38768375444253}, + {:date_time=>"2018-10-29T00:00:00.000Z", :mfi=>35.973926377719295} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/mi_spec.rb b/spec/technical_analysis/indicators/mi_spec.rb index fb133f9..f41b3c0 100644 --- a/spec/technical_analysis/indicators/mi_spec.rb +++ b/spec/technical_analysis/indicators/mi_spec.rb @@ -9,34 +9,35 @@ describe 'Simple Mass Index' do it 'Calculates MI' do output = indicator.calculate(input_data, ema_period: 9, sum_period: 25) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>24.77520633216394}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>24.80084030980544}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>24.924292786436485}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>25.026285600546654}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>25.018142841959207}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>25.04245599370965}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>25.03284918462693}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>25.020764664334674}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>24.964776002066408}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>24.791003528125515}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.564590708470064}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.454674020826847}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>24.303447406952383}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>24.12156756268421}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>23.94958830559542}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>23.879826345759078}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>23.792012619835983}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>23.82241708019551}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>23.835760161850434}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>23.89261610689666}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>23.890966368346767}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>23.8163614080134}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>23.82917406071097} + {:date_time=>"2019-01-09T00:00:00.000Z", :mi=>24.77520633216394}, + {:date_time=>"2019-01-08T00:00:00.000Z", :mi=>24.80084030980544}, + {:date_time=>"2019-01-07T00:00:00.000Z", :mi=>24.924292786436485}, + {:date_time=>"2019-01-04T00:00:00.000Z", :mi=>25.026285600546654}, + {:date_time=>"2019-01-03T00:00:00.000Z", :mi=>25.018142841959207}, + {:date_time=>"2019-01-02T00:00:00.000Z", :mi=>25.04245599370965}, + {:date_time=>"2018-12-31T00:00:00.000Z", :mi=>25.03284918462693}, + {:date_time=>"2018-12-28T00:00:00.000Z", :mi=>25.020764664334674}, + {:date_time=>"2018-12-27T00:00:00.000Z", :mi=>24.964776002066408}, + {:date_time=>"2018-12-26T00:00:00.000Z", :mi=>24.791003528125515}, + {:date_time=>"2018-12-24T00:00:00.000Z", :mi=>24.564590708470064}, + {:date_time=>"2018-12-21T00:00:00.000Z", :mi=>24.454674020826847}, + {:date_time=>"2018-12-20T00:00:00.000Z", :mi=>24.303447406952383}, + {:date_time=>"2018-12-19T00:00:00.000Z", :mi=>24.12156756268421}, + {:date_time=>"2018-12-18T00:00:00.000Z", :mi=>23.94958830559542}, + {:date_time=>"2018-12-17T00:00:00.000Z", :mi=>23.879826345759078}, + {:date_time=>"2018-12-14T00:00:00.000Z", :mi=>23.792012619835983}, + {:date_time=>"2018-12-13T00:00:00.000Z", :mi=>23.82241708019551}, + {:date_time=>"2018-12-12T00:00:00.000Z", :mi=>23.835760161850434}, + {:date_time=>"2018-12-11T00:00:00.000Z", :mi=>23.89261610689666}, + {:date_time=>"2018-12-10T00:00:00.000Z", :mi=>23.890966368346767}, + {:date_time=>"2018-12-07T00:00:00.000Z", :mi=>23.8163614080134}, + {:date_time=>"2018-12-06T00:00:00.000Z", :mi=>23.82917406071097} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/nvi_spec.rb b/spec/technical_analysis/indicators/nvi_spec.rb index 64f7fe4..d200a94 100644 --- a/spec/technical_analysis/indicators/nvi_spec.rb +++ b/spec/technical_analysis/indicators/nvi_spec.rb @@ -9,74 +9,75 @@ describe 'Negative Volume Index' do it 'Calculates NVI' do output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>1002.8410612825647}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>1002.8410612825647}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>1000.9347542454526}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>1001.1573361960799}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>996.888400265283}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>995.9218765502475}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>995.8706437612625}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>996.519622574013}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>996.519622574013}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>999.1070305219995}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>997.8077746966976}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>996.713747493859}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>996.4350307767862}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>997.0069647390503}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>997.0069647390503}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>1000.5726698672554}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>1001.1129093548633}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>1001.8811198113682}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>1001.8811198113682}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>1002.0987352047939}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>1002.0987352047939}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>1004.6386152817257}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>1004.7516224011742}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>1003.6440522637729}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>1001.1761721781198}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>1001.1761721781198}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>1002.1752966566695}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>1002.8707003242093}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>1002.8707003242093}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>1001.7892974768458}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>1004.6281253156736}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>1004.1286907133366}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>1006.0057133670583}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>1006.0057133670583}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>1003.8159323451605}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>1003.2049250951491}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>1003.6370655407939}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>1001.4333482054976}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>1003.5719281883889}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>1000.0}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>1000.0}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>1000.0} + {:date_time=>"2019-01-09T00:00:00.000Z", :nvi=>1002.8410612825647}, + {:date_time=>"2019-01-08T00:00:00.000Z", :nvi=>1002.8410612825647}, + {:date_time=>"2019-01-07T00:00:00.000Z", :nvi=>1000.9347542454526}, + {:date_time=>"2019-01-04T00:00:00.000Z", :nvi=>1001.1573361960799}, + {:date_time=>"2019-01-03T00:00:00.000Z", :nvi=>996.888400265283}, + {:date_time=>"2019-01-02T00:00:00.000Z", :nvi=>996.888400265283}, + {:date_time=>"2018-12-31T00:00:00.000Z", :nvi=>996.888400265283}, + {:date_time=>"2018-12-28T00:00:00.000Z", :nvi=>995.9218765502475}, + {:date_time=>"2018-12-27T00:00:00.000Z", :nvi=>995.8706437612625}, + {:date_time=>"2018-12-26T00:00:00.000Z", :nvi=>996.519622574013}, + {:date_time=>"2018-12-24T00:00:00.000Z", :nvi=>996.519622574013}, + {:date_time=>"2018-12-21T00:00:00.000Z", :nvi=>999.1070305219995}, + {:date_time=>"2018-12-20T00:00:00.000Z", :nvi=>999.1070305219995}, + {:date_time=>"2018-12-19T00:00:00.000Z", :nvi=>999.1070305219995}, + {:date_time=>"2018-12-18T00:00:00.000Z", :nvi=>999.1070305219995}, + {:date_time=>"2018-12-17T00:00:00.000Z", :nvi=>997.8077746966976}, + {:date_time=>"2018-12-14T00:00:00.000Z", :nvi=>997.8077746966976}, + {:date_time=>"2018-12-13T00:00:00.000Z", :nvi=>997.8077746966976}, + {:date_time=>"2018-12-12T00:00:00.000Z", :nvi=>996.713747493859}, + {:date_time=>"2018-12-11T00:00:00.000Z", :nvi=>996.4350307767862}, + {:date_time=>"2018-12-10T00:00:00.000Z", :nvi=>997.0069647390503}, + {:date_time=>"2018-12-07T00:00:00.000Z", :nvi=>997.0069647390503}, + {:date_time=>"2018-12-06T00:00:00.000Z", :nvi=>1000.5726698672554}, + {:date_time=>"2018-12-04T00:00:00.000Z", :nvi=>1000.5726698672554}, + {:date_time=>"2018-12-03T00:00:00.000Z", :nvi=>1000.5726698672554}, + {:date_time=>"2018-11-30T00:00:00.000Z", :nvi=>1000.5726698672554}, + {:date_time=>"2018-11-29T00:00:00.000Z", :nvi=>1001.1129093548633}, + {:date_time=>"2018-11-28T00:00:00.000Z", :nvi=>1001.8811198113682}, + {:date_time=>"2018-11-27T00:00:00.000Z", :nvi=>1001.8811198113682}, + {:date_time=>"2018-11-26T00:00:00.000Z", :nvi=>1002.0987352047939}, + {:date_time=>"2018-11-23T00:00:00.000Z", :nvi=>1002.0987352047939}, + {:date_time=>"2018-11-21T00:00:00.000Z", :nvi=>1004.6386152817257}, + {:date_time=>"2018-11-20T00:00:00.000Z", :nvi=>1004.7516224011742}, + {:date_time=>"2018-11-19T00:00:00.000Z", :nvi=>1004.7516224011742}, + {:date_time=>"2018-11-16T00:00:00.000Z", :nvi=>1004.7516224011742}, + {:date_time=>"2018-11-15T00:00:00.000Z", :nvi=>1003.6440522637729}, + {:date_time=>"2018-11-14T00:00:00.000Z", :nvi=>1001.1761721781198}, + {:date_time=>"2018-11-13T00:00:00.000Z", :nvi=>1001.1761721781198}, + {:date_time=>"2018-11-12T00:00:00.000Z", :nvi=>1002.1752966566695}, + {:date_time=>"2018-11-09T00:00:00.000Z", :nvi=>1002.1752966566695}, + {:date_time=>"2018-11-08T00:00:00.000Z", :nvi=>1002.1752966566695}, + {:date_time=>"2018-11-07T00:00:00.000Z", :nvi=>1002.8707003242093}, + {:date_time=>"2018-11-06T00:00:00.000Z", :nvi=>1002.8707003242093}, + {:date_time=>"2018-11-05T00:00:00.000Z", :nvi=>1001.7892974768458}, + {:date_time=>"2018-11-02T00:00:00.000Z", :nvi=>1004.6281253156736}, + {:date_time=>"2018-11-01T00:00:00.000Z", :nvi=>1004.6281253156736}, + {:date_time=>"2018-10-31T00:00:00.000Z", :nvi=>1004.6281253156736}, + {:date_time=>"2018-10-30T00:00:00.000Z", :nvi=>1004.6281253156736}, + {:date_time=>"2018-10-29T00:00:00.000Z", :nvi=>1004.1286907133366}, + {:date_time=>"2018-10-26T00:00:00.000Z", :nvi=>1006.0057133670583}, + {:date_time=>"2018-10-25T00:00:00.000Z", :nvi=>1006.0057133670583}, + {:date_time=>"2018-10-24T00:00:00.000Z", :nvi=>1003.8159323451605}, + {:date_time=>"2018-10-23T00:00:00.000Z", :nvi=>1003.8159323451605}, + {:date_time=>"2018-10-22T00:00:00.000Z", :nvi=>1003.8159323451605}, + {:date_time=>"2018-10-19T00:00:00.000Z", :nvi=>1003.2049250951491}, + {:date_time=>"2018-10-18T00:00:00.000Z", :nvi=>1003.2049250951491}, + {:date_time=>"2018-10-17T00:00:00.000Z", :nvi=>1003.2049250951491}, + {:date_time=>"2018-10-16T00:00:00.000Z", :nvi=>1003.6370655407939}, + {:date_time=>"2018-10-15T00:00:00.000Z", :nvi=>1001.4333482054976}, + {:date_time=>"2018-10-12T00:00:00.000Z", :nvi=>1003.5719281883889}, + {:date_time=>"2018-10-11T00:00:00.000Z", :nvi=>1000.0}, + {:date_time=>"2018-10-10T00:00:00.000Z", :nvi=>1000.0}, + {:date_time=>"2018-10-09T00:00:00.000Z", :nvi=>1000.0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb index 1f4d52b..34f386a 100644 --- a/spec/technical_analysis/indicators/obv_mean_spec.rb +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -9,64 +9,65 @@ describe 'On-balance Volume Mean' do it 'Calculates OBV Mean (10 day)' do output = indicator.calculate(input_data, period: 10) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-642606913.0}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-654187384.0}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-657547495.0}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-647295525.0}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-636060876.0}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-614324095.0}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-605073347.0}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-587933850.0}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-563282378.0}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-537632267.0}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-520690509.0}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-493338562.0}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-475879438.0}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-463802236.0}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-453894366.0}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-444632138.0}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-436048331.0}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-427847140.0}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-419555627.0}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-412682868.0}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-398147027.0}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-392674222.0}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-378663120.0}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-365710262.0}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-350260027.0}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-334761235.0}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-318827806.0}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-311463969.0}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-302197756.0}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-283664797.0}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-264148349.0}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-236733893.0}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-209152907.0}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-188010709.0}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-176813851.0}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-163172458.0}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-136807276.0}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-111110335.0}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-95269809.0}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-87750647.0}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-80759219.0}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-72480397.0}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-69633236.0}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-59457699.0}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-49972807.0}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-49970286.0}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-62359854.0}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-66215087.0}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-63999351.0}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-61015077.0}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-59574127.0}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-66801824.0}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-65836555.0} + {:date_time=>"2019-01-09T00:00:00.000Z", :obv_mean=>-642606913.0}, + {:date_time=>"2019-01-08T00:00:00.000Z", :obv_mean=>-654187384.0}, + {:date_time=>"2019-01-07T00:00:00.000Z", :obv_mean=>-657547495.0}, + {:date_time=>"2019-01-04T00:00:00.000Z", :obv_mean=>-647295525.0}, + {:date_time=>"2019-01-03T00:00:00.000Z", :obv_mean=>-636060876.0}, + {:date_time=>"2019-01-02T00:00:00.000Z", :obv_mean=>-614324095.0}, + {:date_time=>"2018-12-31T00:00:00.000Z", :obv_mean=>-605073347.0}, + {:date_time=>"2018-12-28T00:00:00.000Z", :obv_mean=>-587933850.0}, + {:date_time=>"2018-12-27T00:00:00.000Z", :obv_mean=>-563282378.0}, + {:date_time=>"2018-12-26T00:00:00.000Z", :obv_mean=>-537632267.0}, + {:date_time=>"2018-12-24T00:00:00.000Z", :obv_mean=>-520690509.0}, + {:date_time=>"2018-12-21T00:00:00.000Z", :obv_mean=>-493338562.0}, + {:date_time=>"2018-12-20T00:00:00.000Z", :obv_mean=>-475879438.0}, + {:date_time=>"2018-12-19T00:00:00.000Z", :obv_mean=>-463802236.0}, + {:date_time=>"2018-12-18T00:00:00.000Z", :obv_mean=>-453894366.0}, + {:date_time=>"2018-12-17T00:00:00.000Z", :obv_mean=>-444632138.0}, + {:date_time=>"2018-12-14T00:00:00.000Z", :obv_mean=>-436048331.0}, + {:date_time=>"2018-12-13T00:00:00.000Z", :obv_mean=>-427847140.0}, + {:date_time=>"2018-12-12T00:00:00.000Z", :obv_mean=>-419555627.0}, + {:date_time=>"2018-12-11T00:00:00.000Z", :obv_mean=>-412682868.0}, + {:date_time=>"2018-12-10T00:00:00.000Z", :obv_mean=>-398147027.0}, + {:date_time=>"2018-12-07T00:00:00.000Z", :obv_mean=>-392674222.0}, + {:date_time=>"2018-12-06T00:00:00.000Z", :obv_mean=>-378663120.0}, + {:date_time=>"2018-12-04T00:00:00.000Z", :obv_mean=>-365710262.0}, + {:date_time=>"2018-12-03T00:00:00.000Z", :obv_mean=>-350260027.0}, + {:date_time=>"2018-11-30T00:00:00.000Z", :obv_mean=>-334761235.0}, + {:date_time=>"2018-11-29T00:00:00.000Z", :obv_mean=>-318827806.0}, + {:date_time=>"2018-11-28T00:00:00.000Z", :obv_mean=>-311463969.0}, + {:date_time=>"2018-11-27T00:00:00.000Z", :obv_mean=>-302197756.0}, + {:date_time=>"2018-11-26T00:00:00.000Z", :obv_mean=>-283664797.0}, + {:date_time=>"2018-11-23T00:00:00.000Z", :obv_mean=>-264148349.0}, + {:date_time=>"2018-11-21T00:00:00.000Z", :obv_mean=>-236733893.0}, + {:date_time=>"2018-11-20T00:00:00.000Z", :obv_mean=>-209152907.0}, + {:date_time=>"2018-11-19T00:00:00.000Z", :obv_mean=>-188010709.0}, + {:date_time=>"2018-11-16T00:00:00.000Z", :obv_mean=>-176813851.0}, + {:date_time=>"2018-11-15T00:00:00.000Z", :obv_mean=>-163172458.0}, + {:date_time=>"2018-11-14T00:00:00.000Z", :obv_mean=>-136807276.0}, + {:date_time=>"2018-11-13T00:00:00.000Z", :obv_mean=>-111110335.0}, + {:date_time=>"2018-11-12T00:00:00.000Z", :obv_mean=>-95269809.0}, + {:date_time=>"2018-11-09T00:00:00.000Z", :obv_mean=>-87750647.0}, + {:date_time=>"2018-11-08T00:00:00.000Z", :obv_mean=>-80759219.0}, + {:date_time=>"2018-11-07T00:00:00.000Z", :obv_mean=>-72480397.0}, + {:date_time=>"2018-11-06T00:00:00.000Z", :obv_mean=>-69633236.0}, + {:date_time=>"2018-11-05T00:00:00.000Z", :obv_mean=>-59457699.0}, + {:date_time=>"2018-11-02T00:00:00.000Z", :obv_mean=>-49972807.0}, + {:date_time=>"2018-11-01T00:00:00.000Z", :obv_mean=>-49970286.0}, + {:date_time=>"2018-10-31T00:00:00.000Z", :obv_mean=>-62359854.0}, + {:date_time=>"2018-10-30T00:00:00.000Z", :obv_mean=>-66215087.0}, + {:date_time=>"2018-10-29T00:00:00.000Z", :obv_mean=>-63999351.0}, + {:date_time=>"2018-10-26T00:00:00.000Z", :obv_mean=>-61015077.0}, + {:date_time=>"2018-10-25T00:00:00.000Z", :obv_mean=>-59574127.0}, + {:date_time=>"2018-10-24T00:00:00.000Z", :obv_mean=>-66801824.0}, + {:date_time=>"2018-10-23T00:00:00.000Z", :obv_mean=>-65836555.0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/obv_spec.rb b/spec/technical_analysis/indicators/obv_spec.rb index 1c6c9b6..c111ee8 100644 --- a/spec/technical_analysis/indicators/obv_spec.rb +++ b/spec/technical_analysis/indicators/obv_spec.rb @@ -9,74 +9,75 @@ describe 'On-balance Volume' do it 'Calculates OBV' do output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-591085010}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-636119380}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-676742290}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-622170850}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-679594500}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-588487660}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-624124730}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-658624120}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-700364720}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-648755870}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-706889720}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-669720490}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-574222590}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-509824360}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-462226690}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-495980180}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-452729760}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-412109400}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-443863610}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-479338290}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-433370250}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-495129250}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-453450570}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-410745660}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-369604410}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-410142110}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-370717850}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-329194270}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-375136020}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-333979880}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-378642200}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-355018230}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-323921990}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-256243310}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-214616490}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-250807820}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-297079480}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-236532140}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-189806430}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-138815400}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-104497640}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-79208370}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-112500010}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-144274730}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-78202560}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>12844000}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-40110070}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-78126880}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-114614810}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-68901120}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-21709420}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-50736760}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-10744640}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-49425810}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-78177350}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-111051680}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-78662400}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-55969520}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-84772070}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-54491620}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-93986390}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-41084070}, - {:date_time=>"2018-10-09T00:00:00.000Z", :value=>0} + {:date_time=>"2019-01-09T00:00:00.000Z", :obv=>-591085010}, + {:date_time=>"2019-01-08T00:00:00.000Z", :obv=>-636119380}, + {:date_time=>"2019-01-07T00:00:00.000Z", :obv=>-676742290}, + {:date_time=>"2019-01-04T00:00:00.000Z", :obv=>-622170850}, + {:date_time=>"2019-01-03T00:00:00.000Z", :obv=>-679594500}, + {:date_time=>"2019-01-02T00:00:00.000Z", :obv=>-588487660}, + {:date_time=>"2018-12-31T00:00:00.000Z", :obv=>-624124730}, + {:date_time=>"2018-12-28T00:00:00.000Z", :obv=>-658624120}, + {:date_time=>"2018-12-27T00:00:00.000Z", :obv=>-700364720}, + {:date_time=>"2018-12-26T00:00:00.000Z", :obv=>-648755870}, + {:date_time=>"2018-12-24T00:00:00.000Z", :obv=>-706889720}, + {:date_time=>"2018-12-21T00:00:00.000Z", :obv=>-669720490}, + {:date_time=>"2018-12-20T00:00:00.000Z", :obv=>-574222590}, + {:date_time=>"2018-12-19T00:00:00.000Z", :obv=>-509824360}, + {:date_time=>"2018-12-18T00:00:00.000Z", :obv=>-462226690}, + {:date_time=>"2018-12-17T00:00:00.000Z", :obv=>-495980180}, + {:date_time=>"2018-12-14T00:00:00.000Z", :obv=>-452729760}, + {:date_time=>"2018-12-13T00:00:00.000Z", :obv=>-412109400}, + {:date_time=>"2018-12-12T00:00:00.000Z", :obv=>-443863610}, + {:date_time=>"2018-12-11T00:00:00.000Z", :obv=>-479338290}, + {:date_time=>"2018-12-10T00:00:00.000Z", :obv=>-433370250}, + {:date_time=>"2018-12-07T00:00:00.000Z", :obv=>-495129250}, + {:date_time=>"2018-12-06T00:00:00.000Z", :obv=>-453450570}, + {:date_time=>"2018-12-04T00:00:00.000Z", :obv=>-410745660}, + {:date_time=>"2018-12-03T00:00:00.000Z", :obv=>-369604410}, + {:date_time=>"2018-11-30T00:00:00.000Z", :obv=>-410142110}, + {:date_time=>"2018-11-29T00:00:00.000Z", :obv=>-370717850}, + {:date_time=>"2018-11-28T00:00:00.000Z", :obv=>-329194270}, + {:date_time=>"2018-11-27T00:00:00.000Z", :obv=>-375136020}, + {:date_time=>"2018-11-26T00:00:00.000Z", :obv=>-333979880}, + {:date_time=>"2018-11-23T00:00:00.000Z", :obv=>-378642200}, + {:date_time=>"2018-11-21T00:00:00.000Z", :obv=>-355018230}, + {:date_time=>"2018-11-20T00:00:00.000Z", :obv=>-323921990}, + {:date_time=>"2018-11-19T00:00:00.000Z", :obv=>-256243310}, + {:date_time=>"2018-11-16T00:00:00.000Z", :obv=>-214616490}, + {:date_time=>"2018-11-15T00:00:00.000Z", :obv=>-250807820}, + {:date_time=>"2018-11-14T00:00:00.000Z", :obv=>-297079480}, + {:date_time=>"2018-11-13T00:00:00.000Z", :obv=>-236532140}, + {:date_time=>"2018-11-12T00:00:00.000Z", :obv=>-189806430}, + {:date_time=>"2018-11-09T00:00:00.000Z", :obv=>-138815400}, + {:date_time=>"2018-11-08T00:00:00.000Z", :obv=>-104497640}, + {:date_time=>"2018-11-07T00:00:00.000Z", :obv=>-79208370}, + {:date_time=>"2018-11-06T00:00:00.000Z", :obv=>-112500010}, + {:date_time=>"2018-11-05T00:00:00.000Z", :obv=>-144274730}, + {:date_time=>"2018-11-02T00:00:00.000Z", :obv=>-78202560}, + {:date_time=>"2018-11-01T00:00:00.000Z", :obv=>12844000}, + {:date_time=>"2018-10-31T00:00:00.000Z", :obv=>-40110070}, + {:date_time=>"2018-10-30T00:00:00.000Z", :obv=>-78126880}, + {:date_time=>"2018-10-29T00:00:00.000Z", :obv=>-114614810}, + {:date_time=>"2018-10-26T00:00:00.000Z", :obv=>-68901120}, + {:date_time=>"2018-10-25T00:00:00.000Z", :obv=>-21709420}, + {:date_time=>"2018-10-24T00:00:00.000Z", :obv=>-50736760}, + {:date_time=>"2018-10-23T00:00:00.000Z", :obv=>-10744640}, + {:date_time=>"2018-10-22T00:00:00.000Z", :obv=>-49425810}, + {:date_time=>"2018-10-19T00:00:00.000Z", :obv=>-78177350}, + {:date_time=>"2018-10-18T00:00:00.000Z", :obv=>-111051680}, + {:date_time=>"2018-10-17T00:00:00.000Z", :obv=>-78662400}, + {:date_time=>"2018-10-16T00:00:00.000Z", :obv=>-55969520}, + {:date_time=>"2018-10-15T00:00:00.000Z", :obv=>-84772070}, + {:date_time=>"2018-10-12T00:00:00.000Z", :obv=>-54491620}, + {:date_time=>"2018-10-11T00:00:00.000Z", :obv=>-93986390}, + {:date_time=>"2018-10-10T00:00:00.000Z", :obv=>-41084070}, + {:date_time=>"2018-10-09T00:00:00.000Z", :obv=>0} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb index 5f6aec7..513eab8 100644 --- a/spec/technical_analysis/indicators/rsi_spec.rb +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -9,60 +9,61 @@ describe 'Relative Strength Index' do it 'Calculates RSI (14 day)' do output = indicator.calculate(input_data, period: 14, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>41.01572095202713}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>38.100858593859655}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>34.80538400125879}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>35.00790948034705}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>27.835833051062522}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>37.90003559360193}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>37.66054013673465}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>35.7297472286003}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>35.63166885267985}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>36.28727515078207}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>22.94077952430888}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>24.757134961511937}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>27.973957664061984}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>30.416532991054595}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>33.926041361905774}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>30.880956115136144}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>31.866930881658718}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>35.61772436774288}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>33.146531878947414}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>32.53565170863392}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>33.115551932880564}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>31.82436379692355}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>35.38441991619841}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>36.58615110748291}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>42.06016450933706}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>35.1442970032345}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>35.760430191057694}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>36.61457624117541}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>29.027101402280678}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>29.211255846774762}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>26.558433878585916}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>28.467396310763007}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>28.552282046348225}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>32.554453236286506}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>36.677863857193564}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>34.550163030510646}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>29.78632377839773}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>32.36268849740294}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>33.31877385045367}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>38.99885805229995}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>41.56699725744853}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>42.51108193242363}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>36.875893042068746}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>34.78189708111985}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>37.93941116682432}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>48.08268788472883}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>44.96841382331871}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>39.38109368376431}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>38.27160493827161} + {:date_time=>"2019-01-09T00:00:00.000Z", :rsi=>41.01572095202713}, + {:date_time=>"2019-01-08T00:00:00.000Z", :rsi=>38.100858593859655}, + {:date_time=>"2019-01-07T00:00:00.000Z", :rsi=>34.80538400125879}, + {:date_time=>"2019-01-04T00:00:00.000Z", :rsi=>35.00790948034705}, + {:date_time=>"2019-01-03T00:00:00.000Z", :rsi=>27.835833051062522}, + {:date_time=>"2019-01-02T00:00:00.000Z", :rsi=>37.90003559360193}, + {:date_time=>"2018-12-31T00:00:00.000Z", :rsi=>37.66054013673465}, + {:date_time=>"2018-12-28T00:00:00.000Z", :rsi=>35.7297472286003}, + {:date_time=>"2018-12-27T00:00:00.000Z", :rsi=>35.63166885267985}, + {:date_time=>"2018-12-26T00:00:00.000Z", :rsi=>36.28727515078207}, + {:date_time=>"2018-12-24T00:00:00.000Z", :rsi=>22.94077952430888}, + {:date_time=>"2018-12-21T00:00:00.000Z", :rsi=>24.757134961511937}, + {:date_time=>"2018-12-20T00:00:00.000Z", :rsi=>27.973957664061984}, + {:date_time=>"2018-12-19T00:00:00.000Z", :rsi=>30.416532991054595}, + {:date_time=>"2018-12-18T00:00:00.000Z", :rsi=>33.926041361905774}, + {:date_time=>"2018-12-17T00:00:00.000Z", :rsi=>30.880956115136144}, + {:date_time=>"2018-12-14T00:00:00.000Z", :rsi=>31.866930881658718}, + {:date_time=>"2018-12-13T00:00:00.000Z", :rsi=>35.61772436774288}, + {:date_time=>"2018-12-12T00:00:00.000Z", :rsi=>33.146531878947414}, + {:date_time=>"2018-12-11T00:00:00.000Z", :rsi=>32.53565170863392}, + {:date_time=>"2018-12-10T00:00:00.000Z", :rsi=>33.115551932880564}, + {:date_time=>"2018-12-07T00:00:00.000Z", :rsi=>31.82436379692355}, + {:date_time=>"2018-12-06T00:00:00.000Z", :rsi=>35.38441991619841}, + {:date_time=>"2018-12-04T00:00:00.000Z", :rsi=>36.58615110748291}, + {:date_time=>"2018-12-03T00:00:00.000Z", :rsi=>42.06016450933706}, + {:date_time=>"2018-11-30T00:00:00.000Z", :rsi=>35.1442970032345}, + {:date_time=>"2018-11-29T00:00:00.000Z", :rsi=>35.760430191057694}, + {:date_time=>"2018-11-28T00:00:00.000Z", :rsi=>36.61457624117541}, + {:date_time=>"2018-11-27T00:00:00.000Z", :rsi=>29.027101402280678}, + {:date_time=>"2018-11-26T00:00:00.000Z", :rsi=>29.211255846774762}, + {:date_time=>"2018-11-23T00:00:00.000Z", :rsi=>26.558433878585916}, + {:date_time=>"2018-11-21T00:00:00.000Z", :rsi=>28.467396310763007}, + {:date_time=>"2018-11-20T00:00:00.000Z", :rsi=>28.552282046348225}, + {:date_time=>"2018-11-19T00:00:00.000Z", :rsi=>32.554453236286506}, + {:date_time=>"2018-11-16T00:00:00.000Z", :rsi=>36.677863857193564}, + {:date_time=>"2018-11-15T00:00:00.000Z", :rsi=>34.550163030510646}, + {:date_time=>"2018-11-14T00:00:00.000Z", :rsi=>29.78632377839773}, + {:date_time=>"2018-11-13T00:00:00.000Z", :rsi=>32.36268849740294}, + {:date_time=>"2018-11-12T00:00:00.000Z", :rsi=>33.31877385045367}, + {:date_time=>"2018-11-09T00:00:00.000Z", :rsi=>38.99885805229995}, + {:date_time=>"2018-11-08T00:00:00.000Z", :rsi=>41.56699725744853}, + {:date_time=>"2018-11-07T00:00:00.000Z", :rsi=>42.51108193242363}, + {:date_time=>"2018-11-06T00:00:00.000Z", :rsi=>36.875893042068746}, + {:date_time=>"2018-11-05T00:00:00.000Z", :rsi=>34.78189708111985}, + {:date_time=>"2018-11-02T00:00:00.000Z", :rsi=>37.93941116682432}, + {:date_time=>"2018-11-01T00:00:00.000Z", :rsi=>48.08268788472883}, + {:date_time=>"2018-10-31T00:00:00.000Z", :rsi=>44.96841382331871}, + {:date_time=>"2018-10-30T00:00:00.000Z", :rsi=>39.38109368376431}, + {:date_time=>"2018-10-29T00:00:00.000Z", :rsi=>38.27160493827161} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index 7e2dfd2..47588d7 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -9,70 +9,71 @@ describe 'Simple Moving Average' do it 'Calculates SMA (5 day)' do output = indicator.calculate(input_data, period: 5, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>148.488}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>149.41}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>150.808}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>152.468}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>154.046}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>157.04199999999997}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>154.824}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>153.422}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>153.54199999999997}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>154.49}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>156.27}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>159.692}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>162.642}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>165.46599999999998}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>167.108}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>167.61999999999998}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>168.752}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>169.35399999999998}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>170.108}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>171.626}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>174.864}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>176.66}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>178.872}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>180.11600000000004}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>179.62600000000003}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>177.58599999999998}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>176.32799999999997}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>175.77400000000003}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>174.982}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>177.30599999999998}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>181.088}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>184.91199999999998}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>186.916}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>189.96599999999998}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>191.628}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>193.816}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>197.23200000000003}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>201.862}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>204.17000000000002}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>205.654}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>206.256}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>209.002}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>210.78400000000002}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>212.69}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>214.82000000000002}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>216.584}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>216.1}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>215.346}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>217.23200000000003}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>218.914}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>219.51600000000002}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>218.76}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>219.97999999999996}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>219.86400000000003}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>219.206}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>219.766}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>219.452}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>218.48600000000002}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>219.43} + {:date_time=>"2019-01-09T00:00:00.000Z", :sma=>148.488}, + {:date_time=>"2019-01-08T00:00:00.000Z", :sma=>149.41}, + {:date_time=>"2019-01-07T00:00:00.000Z", :sma=>150.808}, + {:date_time=>"2019-01-04T00:00:00.000Z", :sma=>152.468}, + {:date_time=>"2019-01-03T00:00:00.000Z", :sma=>154.046}, + {:date_time=>"2019-01-02T00:00:00.000Z", :sma=>157.04199999999997}, + {:date_time=>"2018-12-31T00:00:00.000Z", :sma=>154.824}, + {:date_time=>"2018-12-28T00:00:00.000Z", :sma=>153.422}, + {:date_time=>"2018-12-27T00:00:00.000Z", :sma=>153.54199999999997}, + {:date_time=>"2018-12-26T00:00:00.000Z", :sma=>154.49}, + {:date_time=>"2018-12-24T00:00:00.000Z", :sma=>156.27}, + {:date_time=>"2018-12-21T00:00:00.000Z", :sma=>159.692}, + {:date_time=>"2018-12-20T00:00:00.000Z", :sma=>162.642}, + {:date_time=>"2018-12-19T00:00:00.000Z", :sma=>165.46599999999998}, + {:date_time=>"2018-12-18T00:00:00.000Z", :sma=>167.108}, + {:date_time=>"2018-12-17T00:00:00.000Z", :sma=>167.61999999999998}, + {:date_time=>"2018-12-14T00:00:00.000Z", :sma=>168.752}, + {:date_time=>"2018-12-13T00:00:00.000Z", :sma=>169.35399999999998}, + {:date_time=>"2018-12-12T00:00:00.000Z", :sma=>170.108}, + {:date_time=>"2018-12-11T00:00:00.000Z", :sma=>171.626}, + {:date_time=>"2018-12-10T00:00:00.000Z", :sma=>174.864}, + {:date_time=>"2018-12-07T00:00:00.000Z", :sma=>176.66}, + {:date_time=>"2018-12-06T00:00:00.000Z", :sma=>178.872}, + {:date_time=>"2018-12-04T00:00:00.000Z", :sma=>180.11600000000004}, + {:date_time=>"2018-12-03T00:00:00.000Z", :sma=>179.62600000000003}, + {:date_time=>"2018-11-30T00:00:00.000Z", :sma=>177.58599999999998}, + {:date_time=>"2018-11-29T00:00:00.000Z", :sma=>176.32799999999997}, + {:date_time=>"2018-11-28T00:00:00.000Z", :sma=>175.77400000000003}, + {:date_time=>"2018-11-27T00:00:00.000Z", :sma=>174.982}, + {:date_time=>"2018-11-26T00:00:00.000Z", :sma=>177.30599999999998}, + {:date_time=>"2018-11-23T00:00:00.000Z", :sma=>181.088}, + {:date_time=>"2018-11-21T00:00:00.000Z", :sma=>184.91199999999998}, + {:date_time=>"2018-11-20T00:00:00.000Z", :sma=>186.916}, + {:date_time=>"2018-11-19T00:00:00.000Z", :sma=>189.96599999999998}, + {:date_time=>"2018-11-16T00:00:00.000Z", :sma=>191.628}, + {:date_time=>"2018-11-15T00:00:00.000Z", :sma=>193.816}, + {:date_time=>"2018-11-14T00:00:00.000Z", :sma=>197.23200000000003}, + {:date_time=>"2018-11-13T00:00:00.000Z", :sma=>201.862}, + {:date_time=>"2018-11-12T00:00:00.000Z", :sma=>204.17000000000002}, + {:date_time=>"2018-11-09T00:00:00.000Z", :sma=>205.654}, + {:date_time=>"2018-11-08T00:00:00.000Z", :sma=>206.256}, + {:date_time=>"2018-11-07T00:00:00.000Z", :sma=>209.002}, + {:date_time=>"2018-11-06T00:00:00.000Z", :sma=>210.78400000000002}, + {:date_time=>"2018-11-05T00:00:00.000Z", :sma=>212.69}, + {:date_time=>"2018-11-02T00:00:00.000Z", :sma=>214.82000000000002}, + {:date_time=>"2018-11-01T00:00:00.000Z", :sma=>216.584}, + {:date_time=>"2018-10-31T00:00:00.000Z", :sma=>216.1}, + {:date_time=>"2018-10-30T00:00:00.000Z", :sma=>215.346}, + {:date_time=>"2018-10-29T00:00:00.000Z", :sma=>217.23200000000003}, + {:date_time=>"2018-10-26T00:00:00.000Z", :sma=>218.914}, + {:date_time=>"2018-10-25T00:00:00.000Z", :sma=>219.51600000000002}, + {:date_time=>"2018-10-24T00:00:00.000Z", :sma=>218.76}, + {:date_time=>"2018-10-23T00:00:00.000Z", :sma=>219.97999999999996}, + {:date_time=>"2018-10-22T00:00:00.000Z", :sma=>219.86400000000003}, + {:date_time=>"2018-10-19T00:00:00.000Z", :sma=>219.206}, + {:date_time=>"2018-10-18T00:00:00.000Z", :sma=>219.766}, + {:date_time=>"2018-10-17T00:00:00.000Z", :sma=>219.452}, + {:date_time=>"2018-10-16T00:00:00.000Z", :sma=>218.48600000000002}, + {:date_time=>"2018-10-15T00:00:00.000Z", :sma=>219.43} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/sr_spec.rb b/spec/technical_analysis/indicators/sr_spec.rb index 4d16e71..2359158 100644 --- a/spec/technical_analysis/indicators/sr_spec.rb +++ b/spec/technical_analysis/indicators/sr_spec.rb @@ -9,59 +9,60 @@ describe 'Stochastic Oscillator' do it 'Calculates SR (14 day)' do output = indicator.calculate(input_data, period: 14, signal_period: 3) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>{:sr=>44.44007858546172, :sr_signal=>33.739408752366685}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>{:sr=>34.27340383862123, :sr_signal=>26.631612985573174}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>{:sr=>22.50474383301711, :sr_signal=>15.414319829465327}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>{:sr=>23.1166912850812, :sr_signal=>22.449561749124218}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>{:sr=>0.6215243702976702, :sr_signal=>29.04987430254469}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>{:sr=>43.61046959199379, :sr_signal=>41.21118809340517}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>{:sr=>42.917628945342614, :sr_signal=>38.09610922104404}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>{:sr=>37.105465742879105, :sr_signal=>36.300579364484854}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>{:sr=>34.2652329749104, :sr_signal=>24.155555094877986}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>{:sr=>37.531039375665074, :sr_signal=>13.772232369077116}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>{:sr=>0.6703929340585003, :sr_signal=>2.9825336838014445}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>{:sr=>3.1152647975077716, :sr_signal=>5.080152544595593}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>{:sr=>5.161943319838063, :sr_signal=>9.054487961785336}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>{:sr=>6.963249516440942, :sr_signal=>9.149838987845628}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>{:sr=>15.038271049077, :sr_signal=>10.145121695692445}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>{:sr=>5.447996398018944, :sr_signal=>16.886182356334803}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>{:sr=>9.94909763998139, :sr_signal=>23.970384081443694}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>{:sr=>35.26145303100408, :sr_signal=>28.8292457195742}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>{:sr=>26.700601573345605, :sr_signal=>24.711525960000667}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>{:sr=>24.525682554372914, :sr_signal=>16.048800203857994}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>{:sr=>22.908293752283477, :sr_signal=>13.89015200407954}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>{:sr=>0.712424304917594, :sr_signal=>14.928180772069608}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>{:sr=>18.049737955037553, :sr_signal=>32.719433096383845}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>{:sr=>26.022380056253674, :sr_signal=>36.07538954462583}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>{:sr=>54.0861812778603, :sr_signal=>36.063267521212616}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>{:sr=>28.117607299763502, :sr_signal=>26.965799836520265}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>{:sr=>25.986013986014044, :sr_signal=>20.92157984180065}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>{:sr=>26.79377822378325, :sr_signal=>15.905669844455621}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>{:sr=>9.984947315604659, :sr_signal=>7.140989430040055}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>{:sr=>10.938283993978956, :sr_signal=>4.922619471840783}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>{:sr=>0.49973698053655363, :sr_signal=>2.3224159491234997}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>{:sr=>3.329837441006842, :sr_signal=>2.931860503912096}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>{:sr=>3.137673425827104, :sr_signal=>8.775890351328327}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>{:sr=>2.32807064490234, :sr_signal=>12.744181659747374}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>{:sr=>20.86192698325554, :sr_signal=>12.764205325281347}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>{:sr=>15.04254735108424, :sr_signal=>6.651276276015249}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>{:sr=>2.388141641504267, :sr_signal=>2.0532129671343387}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>{:sr=>2.5231398354572394, :sr_signal=>9.31549269113536}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>{:sr=>1.2483574244415094, :sr_signal=>21.674753063199656}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>{:sr=>24.174980813507332, :sr_signal=>36.326426195958085}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>{:sr=>39.60092095165012, :sr_signal=>35.431056536198575}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>{:sr=>45.203376822716805, :sr_signal=>26.605269889997487}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>{:sr=>21.48887183422879, :sr_signal=>15.172229388808171}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>{:sr=>13.123561013046874, :sr_signal=>37.649110405476506}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>{:sr=>10.904255319148854, :sr_signal=>56.740227701017325}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>{:sr=>88.91951488423378, :sr_signal=>66.35428151414929}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>{:sr=>70.39691289966935, :sr_signal=>46.83290323914804}}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>{:sr=>39.746416758544726, :sr_signal=>32.241290132123396}} + {:date_time=>"2019-01-09T00:00:00.000Z", :sr=>44.44007858546172, :sr_signal=>33.739408752366685}, + {:date_time=>"2019-01-08T00:00:00.000Z", :sr=>34.27340383862123, :sr_signal=>26.631612985573174}, + {:date_time=>"2019-01-07T00:00:00.000Z", :sr=>22.50474383301711, :sr_signal=>15.414319829465327}, + {:date_time=>"2019-01-04T00:00:00.000Z", :sr=>23.1166912850812, :sr_signal=>22.449561749124218}, + {:date_time=>"2019-01-03T00:00:00.000Z", :sr=>0.6215243702976702, :sr_signal=>29.04987430254469}, + {:date_time=>"2019-01-02T00:00:00.000Z", :sr=>43.61046959199379, :sr_signal=>41.21118809340517}, + {:date_time=>"2018-12-31T00:00:00.000Z", :sr=>42.917628945342614, :sr_signal=>38.09610922104404}, + {:date_time=>"2018-12-28T00:00:00.000Z", :sr=>37.105465742879105, :sr_signal=>36.300579364484854}, + {:date_time=>"2018-12-27T00:00:00.000Z", :sr=>34.2652329749104, :sr_signal=>24.155555094877986}, + {:date_time=>"2018-12-26T00:00:00.000Z", :sr=>37.531039375665074, :sr_signal=>13.772232369077116}, + {:date_time=>"2018-12-24T00:00:00.000Z", :sr=>0.6703929340585003, :sr_signal=>2.9825336838014445}, + {:date_time=>"2018-12-21T00:00:00.000Z", :sr=>3.1152647975077716, :sr_signal=>5.080152544595593}, + {:date_time=>"2018-12-20T00:00:00.000Z", :sr=>5.161943319838063, :sr_signal=>9.054487961785336}, + {:date_time=>"2018-12-19T00:00:00.000Z", :sr=>6.963249516440942, :sr_signal=>9.149838987845628}, + {:date_time=>"2018-12-18T00:00:00.000Z", :sr=>15.038271049077, :sr_signal=>10.145121695692445}, + {:date_time=>"2018-12-17T00:00:00.000Z", :sr=>5.447996398018944, :sr_signal=>16.886182356334803}, + {:date_time=>"2018-12-14T00:00:00.000Z", :sr=>9.94909763998139, :sr_signal=>23.970384081443694}, + {:date_time=>"2018-12-13T00:00:00.000Z", :sr=>35.26145303100408, :sr_signal=>28.8292457195742}, + {:date_time=>"2018-12-12T00:00:00.000Z", :sr=>26.700601573345605, :sr_signal=>24.711525960000667}, + {:date_time=>"2018-12-11T00:00:00.000Z", :sr=>24.525682554372914, :sr_signal=>16.048800203857994}, + {:date_time=>"2018-12-10T00:00:00.000Z", :sr=>22.908293752283477, :sr_signal=>13.89015200407954}, + {:date_time=>"2018-12-07T00:00:00.000Z", :sr=>0.712424304917594, :sr_signal=>14.928180772069608}, + {:date_time=>"2018-12-06T00:00:00.000Z", :sr=>18.049737955037553, :sr_signal=>32.719433096383845}, + {:date_time=>"2018-12-04T00:00:00.000Z", :sr=>26.022380056253674, :sr_signal=>36.07538954462583}, + {:date_time=>"2018-12-03T00:00:00.000Z", :sr=>54.0861812778603, :sr_signal=>36.063267521212616}, + {:date_time=>"2018-11-30T00:00:00.000Z", :sr=>28.117607299763502, :sr_signal=>26.965799836520265}, + {:date_time=>"2018-11-29T00:00:00.000Z", :sr=>25.986013986014044, :sr_signal=>20.92157984180065}, + {:date_time=>"2018-11-28T00:00:00.000Z", :sr=>26.79377822378325, :sr_signal=>15.905669844455621}, + {:date_time=>"2018-11-27T00:00:00.000Z", :sr=>9.984947315604659, :sr_signal=>7.140989430040055}, + {:date_time=>"2018-11-26T00:00:00.000Z", :sr=>10.938283993978956, :sr_signal=>4.922619471840783}, + {:date_time=>"2018-11-23T00:00:00.000Z", :sr=>0.49973698053655363, :sr_signal=>2.3224159491234997}, + {:date_time=>"2018-11-21T00:00:00.000Z", :sr=>3.329837441006842, :sr_signal=>2.931860503912096}, + {:date_time=>"2018-11-20T00:00:00.000Z", :sr=>3.137673425827104, :sr_signal=>8.775890351328327}, + {:date_time=>"2018-11-19T00:00:00.000Z", :sr=>2.32807064490234, :sr_signal=>12.744181659747374}, + {:date_time=>"2018-11-16T00:00:00.000Z", :sr=>20.86192698325554, :sr_signal=>12.764205325281347}, + {:date_time=>"2018-11-15T00:00:00.000Z", :sr=>15.04254735108424, :sr_signal=>6.651276276015249}, + {:date_time=>"2018-11-14T00:00:00.000Z", :sr=>2.388141641504267, :sr_signal=>2.0532129671343387}, + {:date_time=>"2018-11-13T00:00:00.000Z", :sr=>2.5231398354572394, :sr_signal=>9.31549269113536}, + {:date_time=>"2018-11-12T00:00:00.000Z", :sr=>1.2483574244415094, :sr_signal=>21.674753063199656}, + {:date_time=>"2018-11-09T00:00:00.000Z", :sr=>24.174980813507332, :sr_signal=>36.326426195958085}, + {:date_time=>"2018-11-08T00:00:00.000Z", :sr=>39.60092095165012, :sr_signal=>35.431056536198575}, + {:date_time=>"2018-11-07T00:00:00.000Z", :sr=>45.203376822716805, :sr_signal=>26.605269889997487}, + {:date_time=>"2018-11-06T00:00:00.000Z", :sr=>21.48887183422879, :sr_signal=>15.172229388808171}, + {:date_time=>"2018-11-05T00:00:00.000Z", :sr=>13.123561013046874, :sr_signal=>37.649110405476506}, + {:date_time=>"2018-11-02T00:00:00.000Z", :sr=>10.904255319148854, :sr_signal=>56.740227701017325}, + {:date_time=>"2018-11-01T00:00:00.000Z", :sr=>88.91951488423378, :sr_signal=>66.35428151414929}, + {:date_time=>"2018-10-31T00:00:00.000Z", :sr=>70.39691289966935, :sr_signal=>46.83290323914804}, + {:date_time=>"2018-10-30T00:00:00.000Z", :sr=>39.746416758544726, :sr_signal=>32.241290132123396} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/trix_spec.rb b/spec/technical_analysis/indicators/trix_spec.rb index bb0203b..39750ad 100644 --- a/spec/technical_analysis/indicators/trix_spec.rb +++ b/spec/technical_analysis/indicators/trix_spec.rb @@ -9,31 +9,32 @@ describe 'Triple Exponential Average' do it 'Calculates TRIX (15 day)' do output = indicator.calculate(input_data, period: 15, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-0.007522826289174942}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-0.007639218329257057}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-0.007682172922749195}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-0.00767662212545961}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-0.007665196848424279}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-0.007658933006361239}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-0.007775594696883065}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-0.007833433859114468}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-0.007824502562605692}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-0.00776162437514068}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-0.007643867247128558}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-0.007455715388896471}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-0.00735126292321306}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-0.007332615495168546}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-0.007365504921638632}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-0.007428539823046746}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-0.007473061875390961}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-0.007537530463588133}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-0.007622995995719011}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-0.007673381215454718} + {:date_time=>"2019-01-09T00:00:00.000Z", :trix=>-0.007522826289174942}, + {:date_time=>"2019-01-08T00:00:00.000Z", :trix=>-0.007639218329257057}, + {:date_time=>"2019-01-07T00:00:00.000Z", :trix=>-0.007682172922749195}, + {:date_time=>"2019-01-04T00:00:00.000Z", :trix=>-0.00767662212545961}, + {:date_time=>"2019-01-03T00:00:00.000Z", :trix=>-0.007665196848424279}, + {:date_time=>"2019-01-02T00:00:00.000Z", :trix=>-0.007658933006361239}, + {:date_time=>"2018-12-31T00:00:00.000Z", :trix=>-0.007775594696883065}, + {:date_time=>"2018-12-28T00:00:00.000Z", :trix=>-0.007833433859114468}, + {:date_time=>"2018-12-27T00:00:00.000Z", :trix=>-0.007824502562605692}, + {:date_time=>"2018-12-26T00:00:00.000Z", :trix=>-0.00776162437514068}, + {:date_time=>"2018-12-24T00:00:00.000Z", :trix=>-0.007643867247128558}, + {:date_time=>"2018-12-21T00:00:00.000Z", :trix=>-0.007455715388896471}, + {:date_time=>"2018-12-20T00:00:00.000Z", :trix=>-0.00735126292321306}, + {:date_time=>"2018-12-19T00:00:00.000Z", :trix=>-0.007332615495168546}, + {:date_time=>"2018-12-18T00:00:00.000Z", :trix=>-0.007365504921638632}, + {:date_time=>"2018-12-17T00:00:00.000Z", :trix=>-0.007428539823046746}, + {:date_time=>"2018-12-14T00:00:00.000Z", :trix=>-0.007473061875390961}, + {:date_time=>"2018-12-13T00:00:00.000Z", :trix=>-0.007537530463588133}, + {:date_time=>"2018-12-12T00:00:00.000Z", :trix=>-0.007622995995719011}, + {:date_time=>"2018-12-11T00:00:00.000Z", :trix=>-0.007673381215454718} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/tsi_spec.rb b/spec/technical_analysis/indicators/tsi_spec.rb index 29346a7..4fe63ff 100644 --- a/spec/technical_analysis/indicators/tsi_spec.rb +++ b/spec/technical_analysis/indicators/tsi_spec.rb @@ -9,37 +9,38 @@ describe 'True Strength Index' do it 'Calculates True Strength Index' do output = indicator.calculate(input_data, low_period: 13, high_period: 25, price_key: :close) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-28.91017661103889}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-30.97413963420104}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-32.39480993311267}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-32.874679857827935}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-33.579027007940994}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-31.495178028566524}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-32.785927300024994}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-34.28080772951784}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-35.41195667338275}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-36.802531445786066}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-38.83883734905748}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-36.202827241203856}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-33.78946079860395}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-32.23640227177938}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-31.30170501401141}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-31.403055885745307}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-30.569488217596724}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-29.91401235092671}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-30.375476807689427}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-30.15935663446155}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-29.704744795960114}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-29.357900955250976}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-28.4796578607378}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-28.752945178257534}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-29.524570107700253}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-32.212798598181024} + {:date_time=>"2019-01-09T00:00:00.000Z", :tsi=>-28.91017661103889}, + {:date_time=>"2019-01-08T00:00:00.000Z", :tsi=>-30.97413963420104}, + {:date_time=>"2019-01-07T00:00:00.000Z", :tsi=>-32.39480993311267}, + {:date_time=>"2019-01-04T00:00:00.000Z", :tsi=>-32.874679857827935}, + {:date_time=>"2019-01-03T00:00:00.000Z", :tsi=>-33.579027007940994}, + {:date_time=>"2019-01-02T00:00:00.000Z", :tsi=>-31.495178028566524}, + {:date_time=>"2018-12-31T00:00:00.000Z", :tsi=>-32.785927300024994}, + {:date_time=>"2018-12-28T00:00:00.000Z", :tsi=>-34.28080772951784}, + {:date_time=>"2018-12-27T00:00:00.000Z", :tsi=>-35.41195667338275}, + {:date_time=>"2018-12-26T00:00:00.000Z", :tsi=>-36.802531445786066}, + {:date_time=>"2018-12-24T00:00:00.000Z", :tsi=>-38.83883734905748}, + {:date_time=>"2018-12-21T00:00:00.000Z", :tsi=>-36.202827241203856}, + {:date_time=>"2018-12-20T00:00:00.000Z", :tsi=>-33.78946079860395}, + {:date_time=>"2018-12-19T00:00:00.000Z", :tsi=>-32.23640227177938}, + {:date_time=>"2018-12-18T00:00:00.000Z", :tsi=>-31.30170501401141}, + {:date_time=>"2018-12-17T00:00:00.000Z", :tsi=>-31.403055885745307}, + {:date_time=>"2018-12-14T00:00:00.000Z", :tsi=>-30.569488217596724}, + {:date_time=>"2018-12-13T00:00:00.000Z", :tsi=>-29.91401235092671}, + {:date_time=>"2018-12-12T00:00:00.000Z", :tsi=>-30.375476807689427}, + {:date_time=>"2018-12-11T00:00:00.000Z", :tsi=>-30.15935663446155}, + {:date_time=>"2018-12-10T00:00:00.000Z", :tsi=>-29.704744795960114}, + {:date_time=>"2018-12-07T00:00:00.000Z", :tsi=>-29.357900955250976}, + {:date_time=>"2018-12-06T00:00:00.000Z", :tsi=>-28.4796578607378}, + {:date_time=>"2018-12-04T00:00:00.000Z", :tsi=>-28.752945178257534}, + {:date_time=>"2018-12-03T00:00:00.000Z", :tsi=>-29.524570107700253}, + {:date_time=>"2018-11-30T00:00:00.000Z", :tsi=>-32.212798598181024} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/uo_spec.rb b/spec/technical_analysis/indicators/uo_spec.rb index aee154c..61740ae 100644 --- a/spec/technical_analysis/indicators/uo_spec.rb +++ b/spec/technical_analysis/indicators/uo_spec.rb @@ -9,46 +9,47 @@ describe 'Ultimate Oscillator' do it 'Calculates UO (5 day)' do output = indicator.calculate(input_data, short_period: 7, medium_period: 14, long_period: 28, short_weight: 4, medium_weight: 2, long_weight: 1) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>47.28872762629681}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>44.828908983561035}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>46.58165158841807}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>50.726610056055335}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>43.660461129633255}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>51.63477005783912}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>46.12625788315007}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>44.736408028234784}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>44.80062908207362}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>38.89197235556109}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>24.01487703769969}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>28.31825074884628}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>30.219780692869403}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>31.693410049073588}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>42.6017793901735}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>38.091246151228205}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>43.99139965247388}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>42.5926187322538}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>46.56343334880161}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>47.39018769748099}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>46.78620949538559}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>46.3795568325064}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>54.531561679403225}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>54.53131218526129}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>58.63742128493122}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>48.76091038333585}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>42.75825214517756}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>39.6100967511459}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>36.448196445521205}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>37.129780535443615}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>30.31628731487427}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>30.12209085444982}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>29.938582222468735}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>33.50557345611348}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>37.48593642184523} + {:date_time=>"2019-01-09T00:00:00.000Z", :uo=>47.28872762629681}, + {:date_time=>"2019-01-08T00:00:00.000Z", :uo=>44.828908983561035}, + {:date_time=>"2019-01-07T00:00:00.000Z", :uo=>46.58165158841807}, + {:date_time=>"2019-01-04T00:00:00.000Z", :uo=>50.726610056055335}, + {:date_time=>"2019-01-03T00:00:00.000Z", :uo=>43.660461129633255}, + {:date_time=>"2019-01-02T00:00:00.000Z", :uo=>51.63477005783912}, + {:date_time=>"2018-12-31T00:00:00.000Z", :uo=>46.12625788315007}, + {:date_time=>"2018-12-28T00:00:00.000Z", :uo=>44.736408028234784}, + {:date_time=>"2018-12-27T00:00:00.000Z", :uo=>44.80062908207362}, + {:date_time=>"2018-12-26T00:00:00.000Z", :uo=>38.89197235556109}, + {:date_time=>"2018-12-24T00:00:00.000Z", :uo=>24.01487703769969}, + {:date_time=>"2018-12-21T00:00:00.000Z", :uo=>28.31825074884628}, + {:date_time=>"2018-12-20T00:00:00.000Z", :uo=>30.219780692869403}, + {:date_time=>"2018-12-19T00:00:00.000Z", :uo=>31.693410049073588}, + {:date_time=>"2018-12-18T00:00:00.000Z", :uo=>42.6017793901735}, + {:date_time=>"2018-12-17T00:00:00.000Z", :uo=>38.091246151228205}, + {:date_time=>"2018-12-14T00:00:00.000Z", :uo=>43.99139965247388}, + {:date_time=>"2018-12-13T00:00:00.000Z", :uo=>42.5926187322538}, + {:date_time=>"2018-12-12T00:00:00.000Z", :uo=>46.56343334880161}, + {:date_time=>"2018-12-11T00:00:00.000Z", :uo=>47.39018769748099}, + {:date_time=>"2018-12-10T00:00:00.000Z", :uo=>46.78620949538559}, + {:date_time=>"2018-12-07T00:00:00.000Z", :uo=>46.3795568325064}, + {:date_time=>"2018-12-06T00:00:00.000Z", :uo=>54.531561679403225}, + {:date_time=>"2018-12-04T00:00:00.000Z", :uo=>54.53131218526129}, + {:date_time=>"2018-12-03T00:00:00.000Z", :uo=>58.63742128493122}, + {:date_time=>"2018-11-30T00:00:00.000Z", :uo=>48.76091038333585}, + {:date_time=>"2018-11-29T00:00:00.000Z", :uo=>42.75825214517756}, + {:date_time=>"2018-11-28T00:00:00.000Z", :uo=>39.6100967511459}, + {:date_time=>"2018-11-27T00:00:00.000Z", :uo=>36.448196445521205}, + {:date_time=>"2018-11-26T00:00:00.000Z", :uo=>37.129780535443615}, + {:date_time=>"2018-11-23T00:00:00.000Z", :uo=>30.31628731487427}, + {:date_time=>"2018-11-21T00:00:00.000Z", :uo=>30.12209085444982}, + {:date_time=>"2018-11-20T00:00:00.000Z", :uo=>29.938582222468735}, + {:date_time=>"2018-11-19T00:00:00.000Z", :uo=>33.50557345611348}, + {:date_time=>"2018-11-16T00:00:00.000Z", :uo=>37.48593642184523} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/vi_spec.rb b/spec/technical_analysis/indicators/vi_spec.rb index e0d6225..ea93f29 100644 --- a/spec/technical_analysis/indicators/vi_spec.rb +++ b/spec/technical_analysis/indicators/vi_spec.rb @@ -9,60 +9,61 @@ describe 'Vortex Indicator' do it 'Calculates VI (14 day)' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=> {:negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=> {:negative_vi=>1.0113586362578701, :positive_vi=>0.8600571901821686}}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=> {:negative_vi=>1.0577860164333046, :positive_vi=>0.813115261460082}}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=> {:negative_vi=>1.0760915145470467, :positive_vi=>0.7417758715458455}}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=> {:negative_vi=>1.114675915889877, :positive_vi=>0.7324951224799482}}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=> {:negative_vi=>1.1146552806731134, :positive_vi=>0.8035916112018086}}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=> {:negative_vi=>1.08671679197995, :positive_vi=>0.8781954887218045}}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=> {:negative_vi=>1.1487474529545731, :positive_vi=>0.8037876063766033}}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=> {:negative_vi=>1.1655798789007923, :positive_vi=>0.729855612482534}}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=> {:negative_vi=>1.2335085243974138, :positive_vi=>0.636331569664903}}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=> {:negative_vi=>1.3088205560235893, :positive_vi=>0.5374882657359492}}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=> {:negative_vi=>1.1606095395904847, :positive_vi=>0.5994780447390226}}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=> {:negative_vi=>1.1525346959374216, :positive_vi=>0.6361329800656076}}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=> {:negative_vi=>1.067568020631851, :positive_vi=>0.7127001934235981}}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=> {:negative_vi=>0.9773071878279123, :positive_vi=>0.8213523084994758}}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=> {:negative_vi=>0.974913770577476, :positive_vi=>0.814344133786256}}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=> {:negative_vi=>0.9867067848168232, :positive_vi=>0.8214508662875287}}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=> {:negative_vi=>1.011590726346824, :positive_vi=>0.8266537121415173}}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=> {:negative_vi=>1.0422719380259118, :positive_vi=>0.8400547615867511}}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=> {:negative_vi=>1.1040510191627, :positive_vi=>0.7505785426583675}}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=> {:negative_vi=>1.136139122315593, :positive_vi=>0.6334605508870221}}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=> {:negative_vi=>1.050514334444714, :positive_vi=>0.7172185077490695}}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=> {:negative_vi=>1.0795256042654737, :positive_vi=>0.7516804020221332}}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=> {:negative_vi=>1.0423007389465182, :positive_vi=>0.7496451535522679}}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=> {:negative_vi=>1.0746012192731307, :positive_vi=>0.8019709726837323}}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=> {:negative_vi=>1.1516224812958684, :positive_vi=>0.6987674707967169}}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=> {:negative_vi=>1.1373201600900555, :positive_vi=>0.6548920237509929}}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=> {:negative_vi=>1.1564601777941095, :positive_vi=>0.6464192792510783}}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=> {:negative_vi=>1.1714346511931206, :positive_vi=>0.6287012609627801}}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=> {:negative_vi=>1.1658984366885399, :positive_vi=>0.65775873808705}}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=> {:negative_vi=>1.2070792620527797, :positive_vi=>0.6046320015251558}}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=> {:negative_vi=>1.1504168141815485, :positive_vi=>0.5639363354788292}}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=> {:negative_vi=>1.1182403853648055, :positive_vi=>0.5634420498548615}}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=> {:negative_vi=>1.018527704309603, :positive_vi=>0.6562081533662589}}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=> {:negative_vi=>1.0499147710692558, :positive_vi=>0.7525644147579889}}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=> {:negative_vi=>1.0787197159390678, :positive_vi=>0.6861446786495575}}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=> {:negative_vi=>1.0659261208578774, :positive_vi=>0.6477869675714517}}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=> {:negative_vi=>1.053272641569953, :positive_vi=>0.6968210271671884}}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=> {:negative_vi=>1.0186513629842182, :positive_vi=>0.7271341463414641}}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=> {:negative_vi=>1.0059420422342082, :positive_vi=>0.7587530852911607}}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=> {:negative_vi=>0.9713674816398625, :positive_vi=>0.8198382448638102}}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=> {:negative_vi=>0.9456323099415208, :positive_vi=>0.8265716374269011}}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=> {:negative_vi=>1.0107777977366625, :positive_vi=>0.7408837794144069}}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=> {:negative_vi=>1.017756255044391, :positive_vi=>0.73372163931486}}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=> {:negative_vi=>0.9506581829483907, :positive_vi=>0.7977446639361122}}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=> {:negative_vi=>0.9510765744895432, :positive_vi=>0.9155241699342749}}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=> {:negative_vi=>0.9136449963918103, :positive_vi=>0.9374983015842824}}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=> {:negative_vi=>1.0400453579079016, :positive_vi=>0.8594387814137219}}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=> {:negative_vi=>0.9987535631315481, :positive_vi=>0.7711714493088508}} + {:date_time=>"2019-01-09T00:00:00.000Z", :negative_vi=>0.9777149447928525, :positive_vi=>0.8609629970246735}, + {:date_time=>"2019-01-08T00:00:00.000Z", :negative_vi=>1.0113586362578701, :positive_vi=>0.8600571901821686}, + {:date_time=>"2019-01-07T00:00:00.000Z", :negative_vi=>1.0577860164333046, :positive_vi=>0.813115261460082}, + {:date_time=>"2019-01-04T00:00:00.000Z", :negative_vi=>1.0760915145470467, :positive_vi=>0.7417758715458455}, + {:date_time=>"2019-01-03T00:00:00.000Z", :negative_vi=>1.114675915889877, :positive_vi=>0.7324951224799482}, + {:date_time=>"2019-01-02T00:00:00.000Z", :negative_vi=>1.1146552806731134, :positive_vi=>0.8035916112018086}, + {:date_time=>"2018-12-31T00:00:00.000Z", :negative_vi=>1.08671679197995, :positive_vi=>0.8781954887218045}, + {:date_time=>"2018-12-28T00:00:00.000Z", :negative_vi=>1.1487474529545731, :positive_vi=>0.8037876063766033}, + {:date_time=>"2018-12-27T00:00:00.000Z", :negative_vi=>1.1655798789007923, :positive_vi=>0.729855612482534}, + {:date_time=>"2018-12-26T00:00:00.000Z", :negative_vi=>1.2335085243974138, :positive_vi=>0.636331569664903}, + {:date_time=>"2018-12-24T00:00:00.000Z", :negative_vi=>1.3088205560235893, :positive_vi=>0.5374882657359492}, + {:date_time=>"2018-12-21T00:00:00.000Z", :negative_vi=>1.1606095395904847, :positive_vi=>0.5994780447390226}, + {:date_time=>"2018-12-20T00:00:00.000Z", :negative_vi=>1.1525346959374216, :positive_vi=>0.6361329800656076}, + {:date_time=>"2018-12-19T00:00:00.000Z", :negative_vi=>1.067568020631851, :positive_vi=>0.7127001934235981}, + {:date_time=>"2018-12-18T00:00:00.000Z", :negative_vi=>0.9773071878279123, :positive_vi=>0.8213523084994758}, + {:date_time=>"2018-12-17T00:00:00.000Z", :negative_vi=>0.974913770577476, :positive_vi=>0.814344133786256}, + {:date_time=>"2018-12-14T00:00:00.000Z", :negative_vi=>0.9867067848168232, :positive_vi=>0.8214508662875287}, + {:date_time=>"2018-12-13T00:00:00.000Z", :negative_vi=>1.011590726346824, :positive_vi=>0.8266537121415173}, + {:date_time=>"2018-12-12T00:00:00.000Z", :negative_vi=>1.0422719380259118, :positive_vi=>0.8400547615867511}, + {:date_time=>"2018-12-11T00:00:00.000Z", :negative_vi=>1.1040510191627, :positive_vi=>0.7505785426583675}, + {:date_time=>"2018-12-10T00:00:00.000Z", :negative_vi=>1.136139122315593, :positive_vi=>0.6334605508870221}, + {:date_time=>"2018-12-07T00:00:00.000Z", :negative_vi=>1.050514334444714, :positive_vi=>0.7172185077490695}, + {:date_time=>"2018-12-06T00:00:00.000Z", :negative_vi=>1.0795256042654737, :positive_vi=>0.7516804020221332}, + {:date_time=>"2018-12-04T00:00:00.000Z", :negative_vi=>1.0423007389465182, :positive_vi=>0.7496451535522679}, + {:date_time=>"2018-12-03T00:00:00.000Z", :negative_vi=>1.0746012192731307, :positive_vi=>0.8019709726837323}, + {:date_time=>"2018-11-30T00:00:00.000Z", :negative_vi=>1.1516224812958684, :positive_vi=>0.6987674707967169}, + {:date_time=>"2018-11-29T00:00:00.000Z", :negative_vi=>1.1373201600900555, :positive_vi=>0.6548920237509929}, + {:date_time=>"2018-11-28T00:00:00.000Z", :negative_vi=>1.1564601777941095, :positive_vi=>0.6464192792510783}, + {:date_time=>"2018-11-27T00:00:00.000Z", :negative_vi=>1.1714346511931206, :positive_vi=>0.6287012609627801}, + {:date_time=>"2018-11-26T00:00:00.000Z", :negative_vi=>1.1658984366885399, :positive_vi=>0.65775873808705}, + {:date_time=>"2018-11-23T00:00:00.000Z", :negative_vi=>1.2070792620527797, :positive_vi=>0.6046320015251558}, + {:date_time=>"2018-11-21T00:00:00.000Z", :negative_vi=>1.1504168141815485, :positive_vi=>0.5639363354788292}, + {:date_time=>"2018-11-20T00:00:00.000Z", :negative_vi=>1.1182403853648055, :positive_vi=>0.5634420498548615}, + {:date_time=>"2018-11-19T00:00:00.000Z", :negative_vi=>1.018527704309603, :positive_vi=>0.6562081533662589}, + {:date_time=>"2018-11-16T00:00:00.000Z", :negative_vi=>1.0499147710692558, :positive_vi=>0.7525644147579889}, + {:date_time=>"2018-11-15T00:00:00.000Z", :negative_vi=>1.0787197159390678, :positive_vi=>0.6861446786495575}, + {:date_time=>"2018-11-14T00:00:00.000Z", :negative_vi=>1.0659261208578774, :positive_vi=>0.6477869675714517}, + {:date_time=>"2018-11-13T00:00:00.000Z", :negative_vi=>1.053272641569953, :positive_vi=>0.6968210271671884}, + {:date_time=>"2018-11-12T00:00:00.000Z", :negative_vi=>1.0186513629842182, :positive_vi=>0.7271341463414641}, + {:date_time=>"2018-11-09T00:00:00.000Z", :negative_vi=>1.0059420422342082, :positive_vi=>0.7587530852911607}, + {:date_time=>"2018-11-08T00:00:00.000Z", :negative_vi=>0.9713674816398625, :positive_vi=>0.8198382448638102}, + {:date_time=>"2018-11-07T00:00:00.000Z", :negative_vi=>0.9456323099415208, :positive_vi=>0.8265716374269011}, + {:date_time=>"2018-11-06T00:00:00.000Z", :negative_vi=>1.0107777977366625, :positive_vi=>0.7408837794144069}, + {:date_time=>"2018-11-05T00:00:00.000Z", :negative_vi=>1.017756255044391, :positive_vi=>0.73372163931486}, + {:date_time=>"2018-11-02T00:00:00.000Z", :negative_vi=>0.9506581829483907, :positive_vi=>0.7977446639361122}, + {:date_time=>"2018-11-01T00:00:00.000Z", :negative_vi=>0.9510765744895432, :positive_vi=>0.9155241699342749}, + {:date_time=>"2018-10-31T00:00:00.000Z", :negative_vi=>0.9136449963918103, :positive_vi=>0.9374983015842824}, + {:date_time=>"2018-10-30T00:00:00.000Z", :negative_vi=>1.0400453579079016, :positive_vi=>0.8594387814137219}, + {:date_time=>"2018-10-29T00:00:00.000Z", :negative_vi=>0.9987535631315481, :positive_vi=>0.7711714493088508} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/vpt_spec.rb b/spec/technical_analysis/indicators/vpt_spec.rb index e12bd3f..0db8506 100644 --- a/spec/technical_analysis/indicators/vpt_spec.rb +++ b/spec/technical_analysis/indicators/vpt_spec.rb @@ -9,73 +9,74 @@ describe 'Volume-Price Trend' do it 'Calculates VPT' do output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-27383899.78109331}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-28148662.548589166}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-28923059.940598898}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-28801593.76496151}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-31252972.592586517}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-22178057.48873647}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-22218723.601326805}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-22552168.387219403}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-22573553.26073845}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-22238622.758734256}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-26332500.093066465}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-25370780.481841102}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-21656330.504158247}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-20031264.8456338}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-18546614.21276814}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-18985158.397835847}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-18582658.71932485}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-17282902.245502096}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-17630301.940948576}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-17729175.804436687}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-17466268.97188952}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-17873132.82137613}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-16386993.991247926}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-15910856.843135413}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-14101104.854714246}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-15517586.252407152}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-15304600.832189944}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-14985612.348714761}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-16752197.088154612}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-16662634.99217477}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-17266635.256844807}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-16666614.749434467}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-16631473.78435367}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-13397928.75906581}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-11748170.533467716}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-12149014.896876106}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-13290943.979317216}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-11580638.32359231}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-11113790.317206156}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-8545161.134440955}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-7883463.234301859}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-7707600.723227796}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-8717279.945880784}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-9060892.67270255}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-7185217.517024899}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-1146038.8004377298}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-1959004.510023763}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-2949972.4593908517}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-3132205.8074873467}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-2274149.490335243}, - {:date_time=>"2018-10-25T00:00:00.000Z", :value=>-1522689.2992524402}, - {:date_time=>"2018-10-24T00:00:00.000Z", :value=>-2158324.481734193}, - {:date_time=>"2018-10-23T00:00:00.000Z", :value=>-786529.9466468699}, - {:date_time=>"2018-10-22T00:00:00.000Z", :value=>-1151165.4943468445}, - {:date_time=>"2018-10-19T00:00:00.000Z", :value=>-1326839.4882367724}, - {:date_time=>"2018-10-18T00:00:00.000Z", :value=>-1827517.8777377433}, - {:date_time=>"2018-10-17T00:00:00.000Z", :value=>-1070464.7668376141}, - {:date_time=>"2018-10-16T00:00:00.000Z", :value=>-972399.6540759658}, - {:date_time=>"2018-10-15T00:00:00.000Z", :value=>-1607126.441433344}, - {:date_time=>"2018-10-12T00:00:00.000Z", :value=>-959554.7990039173}, - {:date_time=>"2018-10-11T00:00:00.000Z", :value=>-2370279.621573285}, - {:date_time=>"2018-10-10T00:00:00.000Z", :value=>-1903264.3174505206} + {:date_time=>"2019-01-09T00:00:00.000Z", :vpt=>-27383899.78109331}, + {:date_time=>"2019-01-08T00:00:00.000Z", :vpt=>-28148662.548589166}, + {:date_time=>"2019-01-07T00:00:00.000Z", :vpt=>-28923059.940598898}, + {:date_time=>"2019-01-04T00:00:00.000Z", :vpt=>-28801593.76496151}, + {:date_time=>"2019-01-03T00:00:00.000Z", :vpt=>-31252972.592586517}, + {:date_time=>"2019-01-02T00:00:00.000Z", :vpt=>-22178057.48873647}, + {:date_time=>"2018-12-31T00:00:00.000Z", :vpt=>-22218723.601326805}, + {:date_time=>"2018-12-28T00:00:00.000Z", :vpt=>-22552168.387219403}, + {:date_time=>"2018-12-27T00:00:00.000Z", :vpt=>-22573553.26073845}, + {:date_time=>"2018-12-26T00:00:00.000Z", :vpt=>-22238622.758734256}, + {:date_time=>"2018-12-24T00:00:00.000Z", :vpt=>-26332500.093066465}, + {:date_time=>"2018-12-21T00:00:00.000Z", :vpt=>-25370780.481841102}, + {:date_time=>"2018-12-20T00:00:00.000Z", :vpt=>-21656330.504158247}, + {:date_time=>"2018-12-19T00:00:00.000Z", :vpt=>-20031264.8456338}, + {:date_time=>"2018-12-18T00:00:00.000Z", :vpt=>-18546614.21276814}, + {:date_time=>"2018-12-17T00:00:00.000Z", :vpt=>-18985158.397835847}, + {:date_time=>"2018-12-14T00:00:00.000Z", :vpt=>-18582658.71932485}, + {:date_time=>"2018-12-13T00:00:00.000Z", :vpt=>-17282902.245502096}, + {:date_time=>"2018-12-12T00:00:00.000Z", :vpt=>-17630301.940948576}, + {:date_time=>"2018-12-11T00:00:00.000Z", :vpt=>-17729175.804436687}, + {:date_time=>"2018-12-10T00:00:00.000Z", :vpt=>-17466268.97188952}, + {:date_time=>"2018-12-07T00:00:00.000Z", :vpt=>-17873132.82137613}, + {:date_time=>"2018-12-06T00:00:00.000Z", :vpt=>-16386993.991247926}, + {:date_time=>"2018-12-04T00:00:00.000Z", :vpt=>-15910856.843135413}, + {:date_time=>"2018-12-03T00:00:00.000Z", :vpt=>-14101104.854714246}, + {:date_time=>"2018-11-30T00:00:00.000Z", :vpt=>-15517586.252407152}, + {:date_time=>"2018-11-29T00:00:00.000Z", :vpt=>-15304600.832189944}, + {:date_time=>"2018-11-28T00:00:00.000Z", :vpt=>-14985612.348714761}, + {:date_time=>"2018-11-27T00:00:00.000Z", :vpt=>-16752197.088154612}, + {:date_time=>"2018-11-26T00:00:00.000Z", :vpt=>-16662634.99217477}, + {:date_time=>"2018-11-23T00:00:00.000Z", :vpt=>-17266635.256844807}, + {:date_time=>"2018-11-21T00:00:00.000Z", :vpt=>-16666614.749434467}, + {:date_time=>"2018-11-20T00:00:00.000Z", :vpt=>-16631473.78435367}, + {:date_time=>"2018-11-19T00:00:00.000Z", :vpt=>-13397928.75906581}, + {:date_time=>"2018-11-16T00:00:00.000Z", :vpt=>-11748170.533467716}, + {:date_time=>"2018-11-15T00:00:00.000Z", :vpt=>-12149014.896876106}, + {:date_time=>"2018-11-14T00:00:00.000Z", :vpt=>-13290943.979317216}, + {:date_time=>"2018-11-13T00:00:00.000Z", :vpt=>-11580638.32359231}, + {:date_time=>"2018-11-12T00:00:00.000Z", :vpt=>-11113790.317206156}, + {:date_time=>"2018-11-09T00:00:00.000Z", :vpt=>-8545161.134440955}, + {:date_time=>"2018-11-08T00:00:00.000Z", :vpt=>-7883463.234301859}, + {:date_time=>"2018-11-07T00:00:00.000Z", :vpt=>-7707600.723227796}, + {:date_time=>"2018-11-06T00:00:00.000Z", :vpt=>-8717279.945880784}, + {:date_time=>"2018-11-05T00:00:00.000Z", :vpt=>-9060892.67270255}, + {:date_time=>"2018-11-02T00:00:00.000Z", :vpt=>-7185217.517024899}, + {:date_time=>"2018-11-01T00:00:00.000Z", :vpt=>-1146038.8004377298}, + {:date_time=>"2018-10-31T00:00:00.000Z", :vpt=>-1959004.510023763}, + {:date_time=>"2018-10-30T00:00:00.000Z", :vpt=>-2949972.4593908517}, + {:date_time=>"2018-10-29T00:00:00.000Z", :vpt=>-3132205.8074873467}, + {:date_time=>"2018-10-26T00:00:00.000Z", :vpt=>-2274149.490335243}, + {:date_time=>"2018-10-25T00:00:00.000Z", :vpt=>-1522689.2992524402}, + {:date_time=>"2018-10-24T00:00:00.000Z", :vpt=>-2158324.481734193}, + {:date_time=>"2018-10-23T00:00:00.000Z", :vpt=>-786529.9466468699}, + {:date_time=>"2018-10-22T00:00:00.000Z", :vpt=>-1151165.4943468445}, + {:date_time=>"2018-10-19T00:00:00.000Z", :vpt=>-1326839.4882367724}, + {:date_time=>"2018-10-18T00:00:00.000Z", :vpt=>-1827517.8777377433}, + {:date_time=>"2018-10-17T00:00:00.000Z", :vpt=>-1070464.7668376141}, + {:date_time=>"2018-10-16T00:00:00.000Z", :vpt=>-972399.6540759658}, + {:date_time=>"2018-10-15T00:00:00.000Z", :vpt=>-1607126.441433344}, + {:date_time=>"2018-10-12T00:00:00.000Z", :vpt=>-959554.7990039173}, + {:date_time=>"2018-10-11T00:00:00.000Z", :vpt=>-2370279.621573285}, + {:date_time=>"2018-10-10T00:00:00.000Z", :vpt=>-1903264.3174505206} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do diff --git a/spec/technical_analysis/indicators/wr_spec.rb b/spec/technical_analysis/indicators/wr_spec.rb index 0bdced6..7284fc9 100644 --- a/spec/technical_analysis/indicators/wr_spec.rb +++ b/spec/technical_analysis/indicators/wr_spec.rb @@ -9,61 +9,62 @@ describe 'Williams %R' do it 'Calculates Williams %R' do output = indicator.calculate(input_data, period: 14) + normalized_output = output.map(&:to_hash) expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :value=>-55.55992141453828}, - {:date_time=>"2019-01-08T00:00:00.000Z", :value=>-65.72659616137877}, - {:date_time=>"2019-01-07T00:00:00.000Z", :value=>-77.4952561669829}, - {:date_time=>"2019-01-04T00:00:00.000Z", :value=>-76.88330871491881}, - {:date_time=>"2019-01-03T00:00:00.000Z", :value=>-99.37847562970234}, - {:date_time=>"2019-01-02T00:00:00.000Z", :value=>-56.38953040800621}, - {:date_time=>"2018-12-31T00:00:00.000Z", :value=>-57.082371054657386}, - {:date_time=>"2018-12-28T00:00:00.000Z", :value=>-62.8945342571209}, - {:date_time=>"2018-12-27T00:00:00.000Z", :value=>-65.7347670250896}, - {:date_time=>"2018-12-26T00:00:00.000Z", :value=>-62.468960624334926}, - {:date_time=>"2018-12-24T00:00:00.000Z", :value=>-99.32960706594149}, - {:date_time=>"2018-12-21T00:00:00.000Z", :value=>-96.88473520249222}, - {:date_time=>"2018-12-20T00:00:00.000Z", :value=>-94.83805668016194}, - {:date_time=>"2018-12-19T00:00:00.000Z", :value=>-93.03675048355906}, - {:date_time=>"2018-12-18T00:00:00.000Z", :value=>-84.961728950923}, - {:date_time=>"2018-12-17T00:00:00.000Z", :value=>-94.55200360198106}, - {:date_time=>"2018-12-14T00:00:00.000Z", :value=>-90.0509023600186}, - {:date_time=>"2018-12-13T00:00:00.000Z", :value=>-64.73854696899592}, - {:date_time=>"2018-12-12T00:00:00.000Z", :value=>-73.29939842665439}, - {:date_time=>"2018-12-11T00:00:00.000Z", :value=>-75.47431744562708}, - {:date_time=>"2018-12-10T00:00:00.000Z", :value=>-77.09170624771653}, - {:date_time=>"2018-12-07T00:00:00.000Z", :value=>-99.28757569508241}, - {:date_time=>"2018-12-06T00:00:00.000Z", :value=>-81.95026204496244}, - {:date_time=>"2018-12-04T00:00:00.000Z", :value=>-73.97761994374633}, - {:date_time=>"2018-12-03T00:00:00.000Z", :value=>-45.9138187221397}, - {:date_time=>"2018-11-30T00:00:00.000Z", :value=>-71.8823927002365}, - {:date_time=>"2018-11-29T00:00:00.000Z", :value=>-74.01398601398596}, - {:date_time=>"2018-11-28T00:00:00.000Z", :value=>-73.20622177621675}, - {:date_time=>"2018-11-27T00:00:00.000Z", :value=>-90.01505268439534}, - {:date_time=>"2018-11-26T00:00:00.000Z", :value=>-89.06171600602104}, - {:date_time=>"2018-11-23T00:00:00.000Z", :value=>-99.50026301946345}, - {:date_time=>"2018-11-21T00:00:00.000Z", :value=>-96.67016255899316}, - {:date_time=>"2018-11-20T00:00:00.000Z", :value=>-96.8623265741729}, - {:date_time=>"2018-11-19T00:00:00.000Z", :value=>-97.67192935509766}, - {:date_time=>"2018-11-16T00:00:00.000Z", :value=>-79.13807301674446}, - {:date_time=>"2018-11-15T00:00:00.000Z", :value=>-84.95745264891575}, - {:date_time=>"2018-11-14T00:00:00.000Z", :value=>-97.61185835849572}, - {:date_time=>"2018-11-13T00:00:00.000Z", :value=>-97.47686016454276}, - {:date_time=>"2018-11-12T00:00:00.000Z", :value=>-98.75164257555849}, - {:date_time=>"2018-11-09T00:00:00.000Z", :value=>-75.82501918649267}, - {:date_time=>"2018-11-08T00:00:00.000Z", :value=>-60.39907904834988}, - {:date_time=>"2018-11-07T00:00:00.000Z", :value=>-54.79662317728319}, - {:date_time=>"2018-11-06T00:00:00.000Z", :value=>-78.51112816577121}, - {:date_time=>"2018-11-05T00:00:00.000Z", :value=>-86.87643898695312}, - {:date_time=>"2018-11-02T00:00:00.000Z", :value=>-89.09574468085114}, - {:date_time=>"2018-11-01T00:00:00.000Z", :value=>-11.080485115766221}, - {:date_time=>"2018-10-31T00:00:00.000Z", :value=>-29.60308710033065}, - {:date_time=>"2018-10-30T00:00:00.000Z", :value=>-60.253583241455274}, - {:date_time=>"2018-10-29T00:00:00.000Z", :value=>-69.64461994076994}, - {:date_time=>"2018-10-26T00:00:00.000Z", :value=>-73.3779264214046} + {:date_time=>"2019-01-09T00:00:00.000Z", :wr=>-55.55992141453828}, + {:date_time=>"2019-01-08T00:00:00.000Z", :wr=>-65.72659616137877}, + {:date_time=>"2019-01-07T00:00:00.000Z", :wr=>-77.4952561669829}, + {:date_time=>"2019-01-04T00:00:00.000Z", :wr=>-76.88330871491881}, + {:date_time=>"2019-01-03T00:00:00.000Z", :wr=>-99.37847562970234}, + {:date_time=>"2019-01-02T00:00:00.000Z", :wr=>-56.38953040800621}, + {:date_time=>"2018-12-31T00:00:00.000Z", :wr=>-57.082371054657386}, + {:date_time=>"2018-12-28T00:00:00.000Z", :wr=>-62.8945342571209}, + {:date_time=>"2018-12-27T00:00:00.000Z", :wr=>-65.7347670250896}, + {:date_time=>"2018-12-26T00:00:00.000Z", :wr=>-62.468960624334926}, + {:date_time=>"2018-12-24T00:00:00.000Z", :wr=>-99.32960706594149}, + {:date_time=>"2018-12-21T00:00:00.000Z", :wr=>-96.88473520249222}, + {:date_time=>"2018-12-20T00:00:00.000Z", :wr=>-94.83805668016194}, + {:date_time=>"2018-12-19T00:00:00.000Z", :wr=>-93.03675048355906}, + {:date_time=>"2018-12-18T00:00:00.000Z", :wr=>-84.961728950923}, + {:date_time=>"2018-12-17T00:00:00.000Z", :wr=>-94.55200360198106}, + {:date_time=>"2018-12-14T00:00:00.000Z", :wr=>-90.0509023600186}, + {:date_time=>"2018-12-13T00:00:00.000Z", :wr=>-64.73854696899592}, + {:date_time=>"2018-12-12T00:00:00.000Z", :wr=>-73.29939842665439}, + {:date_time=>"2018-12-11T00:00:00.000Z", :wr=>-75.47431744562708}, + {:date_time=>"2018-12-10T00:00:00.000Z", :wr=>-77.09170624771653}, + {:date_time=>"2018-12-07T00:00:00.000Z", :wr=>-99.28757569508241}, + {:date_time=>"2018-12-06T00:00:00.000Z", :wr=>-81.95026204496244}, + {:date_time=>"2018-12-04T00:00:00.000Z", :wr=>-73.97761994374633}, + {:date_time=>"2018-12-03T00:00:00.000Z", :wr=>-45.9138187221397}, + {:date_time=>"2018-11-30T00:00:00.000Z", :wr=>-71.8823927002365}, + {:date_time=>"2018-11-29T00:00:00.000Z", :wr=>-74.01398601398596}, + {:date_time=>"2018-11-28T00:00:00.000Z", :wr=>-73.20622177621675}, + {:date_time=>"2018-11-27T00:00:00.000Z", :wr=>-90.01505268439534}, + {:date_time=>"2018-11-26T00:00:00.000Z", :wr=>-89.06171600602104}, + {:date_time=>"2018-11-23T00:00:00.000Z", :wr=>-99.50026301946345}, + {:date_time=>"2018-11-21T00:00:00.000Z", :wr=>-96.67016255899316}, + {:date_time=>"2018-11-20T00:00:00.000Z", :wr=>-96.8623265741729}, + {:date_time=>"2018-11-19T00:00:00.000Z", :wr=>-97.67192935509766}, + {:date_time=>"2018-11-16T00:00:00.000Z", :wr=>-79.13807301674446}, + {:date_time=>"2018-11-15T00:00:00.000Z", :wr=>-84.95745264891575}, + {:date_time=>"2018-11-14T00:00:00.000Z", :wr=>-97.61185835849572}, + {:date_time=>"2018-11-13T00:00:00.000Z", :wr=>-97.47686016454276}, + {:date_time=>"2018-11-12T00:00:00.000Z", :wr=>-98.75164257555849}, + {:date_time=>"2018-11-09T00:00:00.000Z", :wr=>-75.82501918649267}, + {:date_time=>"2018-11-08T00:00:00.000Z", :wr=>-60.39907904834988}, + {:date_time=>"2018-11-07T00:00:00.000Z", :wr=>-54.79662317728319}, + {:date_time=>"2018-11-06T00:00:00.000Z", :wr=>-78.51112816577121}, + {:date_time=>"2018-11-05T00:00:00.000Z", :wr=>-86.87643898695312}, + {:date_time=>"2018-11-02T00:00:00.000Z", :wr=>-89.09574468085114}, + {:date_time=>"2018-11-01T00:00:00.000Z", :wr=>-11.080485115766221}, + {:date_time=>"2018-10-31T00:00:00.000Z", :wr=>-29.60308710033065}, + {:date_time=>"2018-10-30T00:00:00.000Z", :wr=>-60.253583241455274}, + {:date_time=>"2018-10-29T00:00:00.000Z", :wr=>-69.64461994076994}, + {:date_time=>"2018-10-26T00:00:00.000Z", :wr=>-73.3779264214046} ] - expect(output).to eq(expected_output) + expect(normalized_output).to eq(expected_output) end it "Throws exception if not enough data" do From 261cc110f48963bf99b4af4952b010ccb530db5a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 15:53:29 -0500 Subject: [PATCH 38/84] Logic updates - Move helpers into TechnicalAnalysis Module - Change Array class to ArrayHelper - Create validation_spec - Create and add validations for date_time key in datasets - Create tests for date_time validations --- lib/technical_analysis.rb | 2 +- lib/technical_analysis/helpers/array.rb | 35 -------------- .../helpers/array_helper.rb | 27 +++++++++++ .../helpers/stock_calculation.rb | 36 ++++++++------- lib/technical_analysis/helpers/validation.rb | 46 ++++++++++++------- lib/technical_analysis/indicators/adi.rb | 1 + lib/technical_analysis/indicators/adtv.rb | 1 + lib/technical_analysis/indicators/adx.rb | 1 + lib/technical_analysis/indicators/ao.rb | 1 + lib/technical_analysis/indicators/atr.rb | 1 + lib/technical_analysis/indicators/bb.rb | 1 + lib/technical_analysis/indicators/cci.rb | 1 + lib/technical_analysis/indicators/cmf.rb | 1 + lib/technical_analysis/indicators/cr.rb | 1 + lib/technical_analysis/indicators/dc.rb | 1 + lib/technical_analysis/indicators/dlr.rb | 1 + lib/technical_analysis/indicators/dpo.rb | 1 + lib/technical_analysis/indicators/dr.rb | 1 + lib/technical_analysis/indicators/eom.rb | 1 + lib/technical_analysis/indicators/evm.rb | 1 + lib/technical_analysis/indicators/fi.rb | 1 + lib/technical_analysis/indicators/ichimoku.rb | 1 + lib/technical_analysis/indicators/kc.rb | 1 + lib/technical_analysis/indicators/kst.rb | 1 + lib/technical_analysis/indicators/macd.rb | 1 + lib/technical_analysis/indicators/mfi.rb | 1 + lib/technical_analysis/indicators/mi.rb | 1 + lib/technical_analysis/indicators/nvi.rb | 1 + lib/technical_analysis/indicators/obv.rb | 1 + lib/technical_analysis/indicators/obv_mean.rb | 1 + lib/technical_analysis/indicators/rsi.rb | 1 + lib/technical_analysis/indicators/sma.rb | 9 ++-- lib/technical_analysis/indicators/sr.rb | 1 + lib/technical_analysis/indicators/trix.rb | 1 + lib/technical_analysis/indicators/tsi.rb | 1 + lib/technical_analysis/indicators/uo.rb | 1 + lib/technical_analysis/indicators/vi.rb | 1 + lib/technical_analysis/indicators/vpt.rb | 1 + lib/technical_analysis/indicators/wr.rb | 1 + spec/helpers/validaton_spec.rb | 18 ++++++++ 40 files changed, 133 insertions(+), 73 deletions(-) delete mode 100644 lib/technical_analysis/helpers/array.rb create mode 100644 lib/technical_analysis/helpers/array_helper.rb create mode 100644 spec/helpers/validaton_spec.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index 4205c65..1925828 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -1,5 +1,5 @@ # Helpers -require 'technical_analysis/helpers/array' +require 'technical_analysis/helpers/array_helper' require 'technical_analysis/helpers/stock_calculation' require 'technical_analysis/helpers/validation' diff --git a/lib/technical_analysis/helpers/array.rb b/lib/technical_analysis/helpers/array.rb deleted file mode 100644 index 18f7d81..0000000 --- a/lib/technical_analysis/helpers/array.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Array - - def sum - self.inject(0, :+) - end - - def mean - self.sum / self.size.to_f - end - - def sample_variance - m = self.mean - sum = self.inject(0) { |accum, i| accum + (i - m)**2 } - sum / (self.size - 1).to_f - end - - def standard_deviation - Math.sqrt(self.sample_variance) - end - - def sort_by_date_time_asc - if self.first.is_a? Hash - self.sort_by { |row| row[:date_time] } - else - self.sort_by(&:date_time) - end - end - - def sort_by_date_time_desc - sort_by_date_time_asc.reverse - end - - alias_method :average, :mean - -end diff --git a/lib/technical_analysis/helpers/array_helper.rb b/lib/technical_analysis/helpers/array_helper.rb new file mode 100644 index 0000000..1cd5567 --- /dev/null +++ b/lib/technical_analysis/helpers/array_helper.rb @@ -0,0 +1,27 @@ +module TechnicalAnalysis + class ArrayHelper + + def self.sum(data) + data.inject(0, :+) + end + + def self.mean(data) + sum(data) / data.size.to_f + end + + def self.average(data) + sum(data) / data.size.to_f + end + + def self.sample_variance(data) + m = mean(data) + sum = data.inject(0) { |accum, i| accum + (i - m)**2 } + sum / (data.size - 1).to_f + end + + def self.standard_deviation(data) + Math.sqrt(sample_variance(data)) + end + + end +end diff --git a/lib/technical_analysis/helpers/stock_calculation.rb b/lib/technical_analysis/helpers/stock_calculation.rb index 6bd6d26..7c33da6 100644 --- a/lib/technical_analysis/helpers/stock_calculation.rb +++ b/lib/technical_analysis/helpers/stock_calculation.rb @@ -1,23 +1,25 @@ -class StockCalculation +module TechnicalAnalysis + class StockCalculation - def self.true_range(current_high, current_low, previous_close) - [ - (current_high - current_low), - (current_high - previous_close).abs, - (current_low - previous_close).abs - ].max - end + def self.true_range(current_high, current_low, previous_close) + [ + (current_high - current_low), + (current_high - previous_close).abs, + (current_low - previous_close).abs + ].max + end - def self.typical_price(price) - (price[:high] + price[:low] + price[:close]) / 3.0 - end + def self.typical_price(price) + (price[:high] + price[:low] + price[:close]) / 3.0 + end - def self.ema(current_value, data, period, prev_value) - if prev_value.nil? - data.average - else - (current_value - prev_value) * (2.0 / (period + 1.0)) + prev_value + def self.ema(current_value, data, period, prev_value) + if prev_value.nil? + data.average + else + (current_value - prev_value) * (2.0 / (period + 1.0)) + prev_value + end end - end + end end diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index f230ad9..666610a 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -1,25 +1,39 @@ -class Validation +module TechnicalAnalysis + class Validation - def self.validate_numeric_data(data, *keys) - keys.each do |key| - unless data.all? { |v| v[key].is_a? Numeric } - raise ValidationError.new "Invalid Data. '#{key}' is not valid price data." + def self.validate_numeric_data(data, *keys) + keys.each do |key| + unless data.all? { |v| v[key].is_a? Numeric } + raise ValidationError.new "Invalid Data. '#{key}' is not valid price data." + end end end - end - def self.validate_length(data, size) - raise ValidationError.new "Not enough data for that period" if data.size < size - end + def self.validate_length(data, size) + raise ValidationError.new "Not enough data for that period" if data.size < size + end - def self.validate_options(options, valid_options) - raise ValidationError.new "Options must be a hash." unless options.respond_to? :keys - raise ValidationError.new "No valid options provided." unless valid_options + def self.validate_options(options, valid_options) + raise ValidationError.new "Options must be a hash." unless options.respond_to? :keys + raise ValidationError.new "No valid options provided." unless valid_options - return true if (options.keys - valid_options).empty? - raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}" - end + return true if (options.keys - valid_options).empty? + raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}" + end + + def self.validate_date_time_key(data) + first_data = data.first - class ValidationError < StandardError; end + begin + unless first_data.key?(:date_time) && DateTime.parse(first_data[:date_time]) + raise ValidationError.new "Dataset must include date_time field with timestamps" + end + rescue + raise ValidationError.new "Dataset must include date_time field with timestamps" + end + end + class ValidationError < StandardError; end + + end end diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index cfccb9d..fb49de3 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -50,6 +50,7 @@ def self.min_data_size(**params) # @return [Array] An array of AdiValue instances def self.calculate(data) Validation.validate_numeric_data(data, :high, :low, :close, :volume) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index b6b53a2..b966b40 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 22, volume_key: :value) volume_key = volume_key.to_sym Validation.validate_numeric_data(data, volume_key) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 533ec80..0eff2ba 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 8577e2f..691c401 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -55,6 +55,7 @@ def self.calculate(data, short_period: 5, long_period: 34) long_period = long_period.to_i Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, min_data_size(long_period: long_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 39b3d2d..e58d196 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index fff6db2..968f97c 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -58,6 +58,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) 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_date_time_asc diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 677f726..968ee62 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 20, constant: 0.015) constant = constant.to_f Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 6ee707b..ca81bb8 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 20) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 7e32fdc..49519a7 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -53,6 +53,7 @@ def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index 1f865e3..bcce58c 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 20, price_key: :value) 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_date_time_asc diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index fd2a5e2..2caf38f 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -54,6 +54,7 @@ def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 8c69367..3bed7ba 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 20, price_key: :value) 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_date_time_asc diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index a778e8b..ee8a09f 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -53,6 +53,7 @@ def self.calculate(data, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index 1429dc9..a69146c 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index 9ca8bad..3580cc6 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :volume) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index db1250d..d9bc24a 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -52,6 +52,7 @@ def self.min_data_size(**params) def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 33f016f..3eb55dd 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -62,6 +62,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) high_period = high_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(high_period: high_period, medium_period: medium_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index 3569893..f932a29 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index 0e816ee..babb1cd 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -69,6 +69,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(roc4: roc4, sma4: sma4)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index ab4ccdd..609723d 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -59,6 +59,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(slow_period: slow_period, signal_period: signal_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index de392b7..631cdff 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index 003c3b1..ea8ba47 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -55,6 +55,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) sum_period = sum_period.to_i Validation.validate_numeric_data(data, :high, :low) Validation.validate_length(data, min_data_size(ema_period: ema_period, sum_period: sum_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index b3cb8ac..ccc9573 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -52,6 +52,7 @@ def self.min_data_size(**params) def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index c63a7e1..2348acf 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -52,6 +52,7 @@ def self.min_data_size(**params) def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 8286b14..2da895f 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 10) period = period.to_i Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index c62b600..2627d2f 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 14, price_key: :value) 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_date_time_asc diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index 342ead9..d1027de 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -55,21 +55,22 @@ def self.calculate(data, period: 30, price_key: :value) 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] } - data = data.sort_by_date_time_asc - output = [] period_values = [] data.each do |v| period_values << v[price_key] if period_values.size == period - output << SmaValue.new(date_time: v[:date_time], sma: period_values.average) + output << SmaValue.new(date_time: v[:date_time], sma: ArrayHelper.average(period_values)) period_values.shift end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 6384439..c405cd9 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 14, signal_period: 3) signal_period = signal_period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period, signal_period: signal_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 5ca104f..097f93d 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -55,6 +55,7 @@ def self.calculate(data, period: 15, price_key: :value) 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_date_time_asc diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 54eeee6..814fd7f 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -57,6 +57,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) price_key = price_key.to_sym Validation.validate_numeric_data(data, price_key) Validation.validate_length(data, min_data_size(low_period: low_period, high_period: high_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index 0b95255..cc4016b 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -63,6 +63,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh long_weight = long_weight.to_f Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(long_period: long_period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 60fa607..5ae0656 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index cee874e..c3b6d5e 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -52,6 +52,7 @@ def self.min_data_size(**params) def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) + data = data.sort_by_date_time_asc diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index 3c24fa9..f1395fd 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -53,6 +53,7 @@ def self.calculate(data, period: 14) period = period.to_i Validation.validate_numeric_data(data, :high, :low, :close) Validation.validate_length(data, min_data_size(period: period)) + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc diff --git a/spec/helpers/validaton_spec.rb b/spec/helpers/validaton_spec.rb new file mode 100644 index 0000000..0ec3b34 --- /dev/null +++ b/spec/helpers/validaton_spec.rb @@ -0,0 +1,18 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Validation' do + describe "date_time validation" do + input_data = SpecHelper.get_test_data(:close) + + it 'Throws exception for invalid timestamp key' do + bad_date_time_key_data = input_data.each { |row| row[:bad_timestamp_key] = row.delete :date_time } + expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_key_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Throws exception for invalid timestamp format' do + bad_date_time_format_data = input_data.each { |row| row[:date_time] = Date.today } + expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_format_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + end +end From 4c82f05104e5c739c5392756bc2600b30921750f Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 15:55:10 -0500 Subject: [PATCH 39/84] Add date_time_key validation to vpt --- lib/technical_analysis/indicators/vpt.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index c3b6d5e..f2eac7e 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -52,7 +52,7 @@ def self.min_data_size(**params) def self.calculate(data) Validation.validate_numeric_data(data, :close, :volume) Validation.validate_length(data, min_data_size({})) - + Validation.validate_date_time_key(data) data = data.sort_by_date_time_asc From 99ffed4a6b894e9fd9d7650df69c751eea7e724a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 15:58:06 -0500 Subject: [PATCH 40/84] Change logic to sort data by date_time --- lib/technical_analysis/indicators/adi.rb | 9 +++++---- lib/technical_analysis/indicators/adtv.rb | 4 ++-- lib/technical_analysis/indicators/adx.rb | 4 ++-- lib/technical_analysis/indicators/ao.rb | 4 ++-- lib/technical_analysis/indicators/atr.rb | 4 ++-- lib/technical_analysis/indicators/bb.rb | 4 ++-- lib/technical_analysis/indicators/cci.rb | 4 ++-- lib/technical_analysis/indicators/cmf.rb | 4 ++-- lib/technical_analysis/indicators/cr.rb | 4 ++-- lib/technical_analysis/indicators/dc.rb | 4 ++-- lib/technical_analysis/indicators/dlr.rb | 4 ++-- lib/technical_analysis/indicators/dpo.rb | 4 ++-- lib/technical_analysis/indicators/dr.rb | 4 ++-- lib/technical_analysis/indicators/eom.rb | 4 ++-- lib/technical_analysis/indicators/evm.rb | 4 ++-- lib/technical_analysis/indicators/fi.rb | 4 ++-- lib/technical_analysis/indicators/ichimoku.rb | 4 ++-- lib/technical_analysis/indicators/kc.rb | 4 ++-- lib/technical_analysis/indicators/kst.rb | 4 ++-- lib/technical_analysis/indicators/macd.rb | 4 ++-- lib/technical_analysis/indicators/mfi.rb | 4 ++-- lib/technical_analysis/indicators/mi.rb | 4 ++-- lib/technical_analysis/indicators/nvi.rb | 4 ++-- lib/technical_analysis/indicators/obv.rb | 4 ++-- lib/technical_analysis/indicators/obv_mean.rb | 4 ++-- lib/technical_analysis/indicators/rsi.rb | 4 ++-- lib/technical_analysis/indicators/sr.rb | 4 ++-- lib/technical_analysis/indicators/trix.rb | 4 ++-- lib/technical_analysis/indicators/tsi.rb | 4 ++-- lib/technical_analysis/indicators/uo.rb | 4 ++-- lib/technical_analysis/indicators/vi.rb | 4 ++-- lib/technical_analysis/indicators/vpt.rb | 4 ++-- lib/technical_analysis/indicators/wr.rb | 4 ++-- 33 files changed, 69 insertions(+), 68 deletions(-) diff --git a/lib/technical_analysis/indicators/adi.rb b/lib/technical_analysis/indicators/adi.rb index fb49de3..198be86 100644 --- a/lib/technical_analysis/indicators/adi.rb +++ b/lib/technical_analysis/indicators/adi.rb @@ -52,11 +52,11 @@ def self.calculate(data) Validation.validate_numeric_data(data, :high, :low, :close, :volume) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } ad = 0 - ads = [] clv = 0 + output = [] prev_ad = 0 data.each_with_index do |values, i| @@ -70,9 +70,10 @@ def self.calculate(data) prev_ad = ad date_time = values[:date_time] - ads << AdiValue.new(date_time: date_time, adi: ad) + output << AdiValue.new(date_time: date_time, adi: ad) end - ads.sort_by_date_time_desc + + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index b966b40..0af0e80 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 22, volume_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -70,7 +70,7 @@ def self.calculate(data, period: 22, volume_key: :value) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 0eff2ba..14ff139 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } dx_values = [] output = [] @@ -100,7 +100,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end private_class_method def self.calculate_dm(current_price, prev_price) diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 691c401..4774f22 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -57,7 +57,7 @@ def self.calculate(data, short_period: 5, long_period: 34) Validation.validate_length(data, min_data_size(long_period: long_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } midpoint_values = [] output = [] @@ -77,7 +77,7 @@ def self.calculate(data, short_period: 5, long_period: 34) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index e58d196..1629eb6 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -81,7 +81,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index 968f97c..c3f9cf0 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -60,7 +60,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -85,7 +85,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 968ee62..639f261 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 20, constant: 0.015) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] typical_prices = [] @@ -77,7 +77,7 @@ def self.calculate(data, period: 20, constant: 0.015) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index ca81bb8..077a45d 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 20) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -77,7 +77,7 @@ def self.calculate(data, period: 20) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/cr.rb b/lib/technical_analysis/indicators/cr.rb index 49519a7..55fcc14 100644 --- a/lib/technical_analysis/indicators/cr.rb +++ b/lib/technical_analysis/indicators/cr.rb @@ -55,7 +55,7 @@ def self.calculate(data, price_key: :value) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] start_price = data.first[price_key] @@ -67,7 +67,7 @@ def self.calculate(data, price_key: :value) ) end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/dc.rb b/lib/technical_analysis/indicators/dc.rb index bcce58c..1af1712 100644 --- a/lib/technical_analysis/indicators/dc.rb +++ b/lib/technical_analysis/indicators/dc.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 20, price_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -76,7 +76,7 @@ def self.calculate(data, period: 20, price_key: :value) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/dlr.rb b/lib/technical_analysis/indicators/dlr.rb index 2caf38f..14569af 100644 --- a/lib/technical_analysis/indicators/dlr.rb +++ b/lib/technical_analysis/indicators/dlr.rb @@ -56,7 +56,7 @@ def self.calculate(data, price_key: :value) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_price = data.first[price_key].to_f @@ -69,7 +69,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index 3bed7ba..c388de4 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 20, price_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } index = period + (period / 2) - 1 midpoint_index = (period / 2) + 1 @@ -78,7 +78,7 @@ def self.calculate(data, period: 20, price_key: :value) index += 1 end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/dr.rb b/lib/technical_analysis/indicators/dr.rb index ee8a09f..2be3d13 100644 --- a/lib/technical_analysis/indicators/dr.rb +++ b/lib/technical_analysis/indicators/dr.rb @@ -55,7 +55,7 @@ def self.calculate(data, price_key: :value) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_price = data.first[price_key].to_f @@ -68,7 +68,7 @@ def self.calculate(data, price_key: :value) prev_price = current_price end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index a69146c..fb2044f 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -76,7 +76,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index 3580cc6..c3b643a 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -76,7 +76,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/fi.rb b/lib/technical_analysis/indicators/fi.rb index d9bc24a..6587230 100644 --- a/lib/technical_analysis/indicators/fi.rb +++ b/lib/technical_analysis/indicators/fi.rb @@ -54,7 +54,7 @@ def self.calculate(data) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_price = data.shift @@ -67,7 +67,7 @@ def self.calculate(data) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/ichimoku.rb b/lib/technical_analysis/indicators/ichimoku.rb index 3eb55dd..a211098 100644 --- a/lib/technical_analysis/indicators/ichimoku.rb +++ b/lib/technical_analysis/indicators/ichimoku.rb @@ -64,7 +64,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) Validation.validate_length(data, min_data_size(high_period: high_period, medium_period: medium_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } index = high_period + medium_period - 2 output = [] @@ -90,7 +90,7 @@ def self.calculate(data, low_period: 9, medium_period: 26, high_period: 52) index += 1 end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end private_class_method def self.lowest_low(prices) diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index f932a29..d655757 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 10) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -83,7 +83,7 @@ def self.calculate(data, period: 10) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index babb1cd..e33e58a 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -71,7 +71,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: Validation.validate_length(data, min_data_size(roc4: roc4, sma4: sma4)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } index = roc4 + sma4 - 2 output = [] @@ -90,7 +90,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: index += 1 end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end private_class_method def self.calculate_rcma(data, index, price_key, roc, sma) diff --git a/lib/technical_analysis/indicators/macd.rb b/lib/technical_analysis/indicators/macd.rb index 609723d..a1c988e 100644 --- a/lib/technical_analysis/indicators/macd.rb +++ b/lib/technical_analysis/indicators/macd.rb @@ -61,7 +61,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri Validation.validate_length(data, min_data_size(slow_period: slow_period, signal_period: signal_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } macd_values = [] output = [] @@ -103,7 +103,7 @@ def self.calculate(data, fast_period: 12, slow_period: 26, signal_period: 9, pri end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 631cdff..bf55363 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_typical_price = StockCalculation.typical_price(data.first) @@ -91,7 +91,7 @@ def self.calculate(data, period: 14) prev_typical_price = typical_price end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index ea8ba47..f07bc28 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -57,7 +57,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) Validation.validate_length(data, min_data_size(ema_period: ema_period, sum_period: sum_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } double_emas = [] high_low_diffs = [] @@ -93,7 +93,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/nvi.rb b/lib/technical_analysis/indicators/nvi.rb index ccc9573..5936278 100644 --- a/lib/technical_analysis/indicators/nvi.rb +++ b/lib/technical_analysis/indicators/nvi.rb @@ -54,7 +54,7 @@ def self.calculate(data) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } nvi_cumulative = 1_000.00 output = [] @@ -74,7 +74,7 @@ def self.calculate(data) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/obv.rb b/lib/technical_analysis/indicators/obv.rb index 2348acf..67e6cd8 100644 --- a/lib/technical_analysis/indicators/obv.rb +++ b/lib/technical_analysis/indicators/obv.rb @@ -54,7 +54,7 @@ def self.calculate(data) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } current_obv = 0 output = [] @@ -76,7 +76,7 @@ def self.calculate(data) prior_close = close end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 2da895f..79628f0 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 10) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } current_obv = 0 obvs = [] @@ -82,7 +82,7 @@ def self.calculate(data, period: 10) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 2627d2f..1c1c7a7 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 14, price_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_price = data.shift[price_key] @@ -105,7 +105,7 @@ def self.calculate(data, period: 14, price_key: :value) prev_price = v[price_key] end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index c405cd9..1f2c577 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 14, signal_period: 3) Validation.validate_length(data, min_data_size(period: period, signal_period: signal_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } high_low_values = [] output = [] @@ -90,7 +90,7 @@ def self.calculate(data, period: 14, signal_period: 3) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/trix.rb b/lib/technical_analysis/indicators/trix.rb index 097f93d..5bd3b28 100644 --- a/lib/technical_analysis/indicators/trix.rb +++ b/lib/technical_analysis/indicators/trix.rb @@ -57,7 +57,7 @@ def self.calculate(data, period: 15, price_key: :value) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } ema1 = [] ema2 = [] @@ -99,7 +99,7 @@ def self.calculate(data, period: 15, price_key: :value) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 814fd7f..47a48a8 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -59,7 +59,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) Validation.validate_length(data, min_data_size(low_period: low_period, high_period: high_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } high_emas = [] high_multiplier = (2.0 / (high_period + 1.0)) @@ -98,7 +98,7 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) prev_price = current_price end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end private_class_method def self.process_ema(current_value, data, multiplier, period, store) diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index cc4016b..5f6cfaa 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -65,7 +65,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh Validation.validate_length(data, min_data_size(long_period: long_period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -95,7 +95,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh prior_close = v[:close] end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end private_class_method def self.calculate_average(period, data) diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index 5ae0656..cc651fe 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -85,7 +85,7 @@ def self.calculate(data, period: 14) prev_price = v end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/vpt.rb b/lib/technical_analysis/indicators/vpt.rb index f2eac7e..383e3de 100644 --- a/lib/technical_analysis/indicators/vpt.rb +++ b/lib/technical_analysis/indicators/vpt.rb @@ -54,7 +54,7 @@ def self.calculate(data) Validation.validate_length(data, min_data_size({})) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] prev_price = data.shift @@ -67,7 +67,7 @@ def self.calculate(data) prev_pvt = pvt end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end diff --git a/lib/technical_analysis/indicators/wr.rb b/lib/technical_analysis/indicators/wr.rb index f1395fd..943a1fd 100644 --- a/lib/technical_analysis/indicators/wr.rb +++ b/lib/technical_analysis/indicators/wr.rb @@ -55,7 +55,7 @@ def self.calculate(data, period: 14) Validation.validate_length(data, min_data_size(period: period)) Validation.validate_date_time_key(data) - data = data.sort_by_date_time_asc + data = data.sort_by { |row| row[:date_time] } output = [] period_values = [] @@ -75,7 +75,7 @@ def self.calculate(data, period: 14) end end - output.sort_by_date_time_desc + output.sort_by(&:date_time).reverse end end From 2f892cfc9b309ac809b2cc60ab0239e11f2caec8 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:04:09 -0500 Subject: [PATCH 41/84] Update references to sum ArrayHelper method --- lib/technical_analysis/indicators/adx.rb | 6 +++--- lib/technical_analysis/indicators/cmf.rb | 4 ++-- lib/technical_analysis/indicators/kst.rb | 2 +- lib/technical_analysis/indicators/mfi.rb | 4 ++-- lib/technical_analysis/indicators/mi.rb | 2 +- lib/technical_analysis/indicators/uo.rb | 6 +++--- lib/technical_analysis/indicators/vi.rb | 6 +++--- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 14ff139..a9678ad 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -120,9 +120,9 @@ def self.calculate(data, period: 14) private_class_method def self.smooth_periodic_values(period, periodic_values, smoothed_values) if smoothed_values.empty? - tr_period = periodic_values.map { |pv| pv[:tr] }.sum - dm_pos_period = periodic_values.map { |pv| pv[:dm_pos] }.sum - dm_neg_period = periodic_values.map { |pv| pv[:dm_neg] }.sum + tr_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:tr] }) + dm_pos_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:dm_pos] }) + dm_neg_period = ArrayHelper.sum(periodic_values.map { |pv| pv[:dm_neg] }) else prev_value = smoothed_values.last current_value = periodic_values.last diff --git a/lib/technical_analysis/indicators/cmf.rb b/lib/technical_analysis/indicators/cmf.rb index 077a45d..683f7e8 100644 --- a/lib/technical_analysis/indicators/cmf.rb +++ b/lib/technical_analysis/indicators/cmf.rb @@ -67,8 +67,8 @@ def self.calculate(data, period: 20) period_values << { volume: v[:volume], mf_volume: mf_volume } if period_values.size == period - volume_sum = period_values.map { |pv| pv[:volume] }.sum - mf_volume_sum = period_values.map { |pv| pv[:mf_volume] }.sum + volume_sum = ArrayHelper.sum(period_values.map { |pv| pv[:volume] }) + mf_volume_sum = ArrayHelper.sum(period_values.map { |pv| pv[:mf_volume] }) cmf = mf_volume_sum / volume_sum output << CmfValue.new(date_time: v[:date_time], cmf: cmf) diff --git a/lib/technical_analysis/indicators/kst.rb b/lib/technical_analysis/indicators/kst.rb index e33e58a..076deee 100644 --- a/lib/technical_analysis/indicators/kst.rb +++ b/lib/technical_analysis/indicators/kst.rb @@ -104,7 +104,7 @@ def self.calculate(data, roc1: 10, roc2: 15, roc3: 20, roc4: 30, sma1: 10, sma2: roc_data << (last_price - starting_price) / starting_price * 100 end - roc_data.sum / sma.to_f + ArrayHelper.sum(roc_data) / sma.to_f end end diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index bf55363..375ffaf 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -77,8 +77,8 @@ def self.calculate(data, period: 14) raw_money_flows << money_flow if raw_money_flows.size == period - positive_period_flows = raw_money_flows.map { |rmf| rmf.positive? ? rmf : 0 }.sum - negative_period_flows = raw_money_flows.map { |rmf| rmf.negative? ? rmf.abs : 0 }.sum + positive_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.positive? ? rmf : 0 }) + negative_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.negative? ? rmf.abs : 0 }) money_flow_ratio = (positive_period_flows / negative_period_flows) mfi = (100.00 - (100.00 / (1.0 + money_flow_ratio))) diff --git a/lib/technical_analysis/indicators/mi.rb b/lib/technical_analysis/indicators/mi.rb index f07bc28..8fb495c 100644 --- a/lib/technical_analysis/indicators/mi.rb +++ b/lib/technical_analysis/indicators/mi.rb @@ -80,7 +80,7 @@ def self.calculate(data, ema_period: 9, sum_period: 25) ratio_of_emas << (single_ema / double_ema) if ratio_of_emas.size == sum_period - output << MiValue.new(date_time: v[:date_time], mi: ratio_of_emas.sum) + output << MiValue.new(date_time: v[:date_time], mi: ArrayHelper.sum(ratio_of_emas)) double_emas.shift ratio_of_emas.shift diff --git a/lib/technical_analysis/indicators/uo.rb b/lib/technical_analysis/indicators/uo.rb index 5f6cfaa..3a53977 100644 --- a/lib/technical_analysis/indicators/uo.rb +++ b/lib/technical_analysis/indicators/uo.rb @@ -70,7 +70,7 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh output = [] period_values = [] prior_close = data.shift[:close] - sum_of_weights = [short_weight, medium_weight, long_weight].sum + sum_of_weights = ArrayHelper.sum([short_weight, medium_weight, long_weight]) data.each do |v| min_low_p_close = [v[:low], prior_close].min @@ -99,8 +99,8 @@ def self.calculate(data, short_period: 7, medium_period: 14, long_period: 28, sh end private_class_method def self.calculate_average(period, data) - buying_pressures_sum = data.last(period).map { |d| d[:buying_pressure] }.sum - true_ranges_sum = data.last(period).map { |d| d[:true_range] }.sum + buying_pressures_sum = ArrayHelper.sum(data.last(period).map { |d| d[:buying_pressure] }) + true_ranges_sum = ArrayHelper.sum(data.last(period).map { |d| d[:true_range] }) buying_pressures_sum / true_ranges_sum end diff --git a/lib/technical_analysis/indicators/vi.rb b/lib/technical_analysis/indicators/vi.rb index cc651fe..2a7f9e1 100644 --- a/lib/technical_analysis/indicators/vi.rb +++ b/lib/technical_analysis/indicators/vi.rb @@ -69,9 +69,9 @@ def self.calculate(data, period: 14) period_values << { pos_vm: positive_vm, neg_vm: negative_vm, tr: tr } if period_values.size == period - pos_vm_period = period_values.map { |pv| pv[:pos_vm] }.sum - neg_vm_period = period_values.map { |pv| pv[:neg_vm] }.sum - tr_period = period_values.map { |pv| pv[:tr] }.sum + pos_vm_period = ArrayHelper.sum(period_values.map { |pv| pv[:pos_vm] }) + neg_vm_period = ArrayHelper.sum(period_values.map { |pv| pv[:neg_vm] }) + tr_period = ArrayHelper.sum(period_values.map { |pv| pv[:tr] }) output << ViValue.new( date_time: v[:date_time], From 76e40b6f821ddbf36e95b7bb41ba931965390326 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:13:00 -0500 Subject: [PATCH 42/84] Update references to average and mean ArrayHelper --- lib/technical_analysis/helpers/stock_calculation.rb | 2 +- lib/technical_analysis/indicators/adtv.rb | 2 +- lib/technical_analysis/indicators/adx.rb | 2 +- lib/technical_analysis/indicators/ao.rb | 4 ++-- lib/technical_analysis/indicators/atr.rb | 2 +- lib/technical_analysis/indicators/bb.rb | 2 +- lib/technical_analysis/indicators/cci.rb | 4 ++-- lib/technical_analysis/indicators/dpo.rb | 2 +- lib/technical_analysis/indicators/eom.rb | 2 +- lib/technical_analysis/indicators/evm.rb | 2 +- lib/technical_analysis/indicators/kc.rb | 4 ++-- lib/technical_analysis/indicators/obv_mean.rb | 2 +- lib/technical_analysis/indicators/rsi.rb | 4 ++-- lib/technical_analysis/indicators/sr.rb | 2 +- lib/technical_analysis/indicators/tsi.rb | 4 ++-- 15 files changed, 20 insertions(+), 20 deletions(-) diff --git a/lib/technical_analysis/helpers/stock_calculation.rb b/lib/technical_analysis/helpers/stock_calculation.rb index 7c33da6..6da25da 100644 --- a/lib/technical_analysis/helpers/stock_calculation.rb +++ b/lib/technical_analysis/helpers/stock_calculation.rb @@ -15,7 +15,7 @@ def self.typical_price(price) def self.ema(current_value, data, period, prev_value) if prev_value.nil? - data.average + ArrayHelper.average(data) else (current_value - prev_value) * (2.0 / (period + 1.0)) + prev_value end diff --git a/lib/technical_analysis/indicators/adtv.rb b/lib/technical_analysis/indicators/adtv.rb index 0af0e80..de0fdb9 100644 --- a/lib/technical_analysis/indicators/adtv.rb +++ b/lib/technical_analysis/indicators/adtv.rb @@ -65,7 +65,7 @@ def self.calculate(data, period: 22, volume_key: :value) data.each do |v| period_values << v[volume_key] if period_values.size == period - output << AdtvValue.new(date_time: v[:date_time], adtv: period_values.average) + output << AdtvValue.new(date_time: v[:date_time], adtv: ArrayHelper.average(period_values)) period_values.shift end end diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index a9678ad..1bcda37 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -83,7 +83,7 @@ def self.calculate(data, period: 14) if dx_values.size == period if prev_adx.nil? - adx = dx_values.average + adx = ArrayHelper.average(dx_values) else adx = ((prev_adx * 13) + dx) / period.to_f end diff --git a/lib/technical_analysis/indicators/ao.rb b/lib/technical_analysis/indicators/ao.rb index 4774f22..3ca8fbd 100644 --- a/lib/technical_analysis/indicators/ao.rb +++ b/lib/technical_analysis/indicators/ao.rb @@ -67,8 +67,8 @@ def self.calculate(data, short_period: 5, long_period: 34) midpoint_values << midpoint if midpoint_values.size == long_period - short_period_sma = midpoint_values.last(short_period).average - long_period_sma = midpoint_values.average + short_period_sma = ArrayHelper.average(midpoint_values.last(short_period)) + long_period_sma = ArrayHelper.average(midpoint_values) value = short_period_sma - long_period_sma output << AoValue.new(date_time: v[:date_time], ao: value) diff --git a/lib/technical_analysis/indicators/atr.rb b/lib/technical_analysis/indicators/atr.rb index 1629eb6..fc47494 100644 --- a/lib/technical_analysis/indicators/atr.rb +++ b/lib/technical_analysis/indicators/atr.rb @@ -68,7 +68,7 @@ def self.calculate(data, period: 14) if period_values.size == period if output.empty? - atr = period_values.average + atr = ArrayHelper.average(period_values) else atr = (output.last.atr * (period - 1.0) + tr) / period.to_f end diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index c3f9cf0..c5018c0 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -69,7 +69,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) period_values << v[price_key] if period_values.size == period - mb = period_values.average + mb = ArrayHelper.average(period_values) sd = period_values.standard_deviation ub = mb + standard_deviations * sd lb = mb - standard_deviations * sd diff --git a/lib/technical_analysis/indicators/cci.rb b/lib/technical_analysis/indicators/cci.rb index 639f261..75f6b7b 100644 --- a/lib/technical_analysis/indicators/cci.rb +++ b/lib/technical_analysis/indicators/cci.rb @@ -67,8 +67,8 @@ def self.calculate(data, period: 20, constant: 0.015) typical_prices << typical_price if typical_prices.size == period - period_sma = typical_prices.average - mean_deviation = typical_prices.map { |tp| (tp - period_sma).abs }.mean + period_sma = ArrayHelper.average(typical_prices) + mean_deviation = ArrayHelper.mean(typical_prices.map { |tp| (tp - period_sma).abs }) cci = (typical_price - period_sma) / (constant * mean_deviation) output << CciValue.new(date_time: v[:date_time], cci: cci) diff --git a/lib/technical_analysis/indicators/dpo.rb b/lib/technical_analysis/indicators/dpo.rb index c388de4..b1fdf84 100644 --- a/lib/technical_analysis/indicators/dpo.rb +++ b/lib/technical_analysis/indicators/dpo.rb @@ -69,7 +69,7 @@ def self.calculate(data, period: 20, price_key: :value) current_price = current_record[price_key] sma_range = (index - midpoint_index - period + 2)..(index - midpoint_index + 1) - midpoint_period_sma = data[sma_range].map { |v| v[price_key] }.average + midpoint_period_sma = ArrayHelper.average(data[sma_range].map { |v| v[price_key] }) dpo = (current_price - midpoint_period_sma) diff --git a/lib/technical_analysis/indicators/eom.rb b/lib/technical_analysis/indicators/eom.rb index fb2044f..e46f8f8 100644 --- a/lib/technical_analysis/indicators/eom.rb +++ b/lib/technical_analysis/indicators/eom.rb @@ -69,7 +69,7 @@ def self.calculate(data, period: 14) period_values << emv if period_values.size == period - output << EomValue.new(date_time: v[:date_time], eom: period_values.average) + output << EomValue.new(date_time: v[:date_time], eom: ArrayHelper.average(period_values)) period_values.shift end diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb index c3b643a..2991dfe 100644 --- a/lib/technical_analysis/indicators/evm.rb +++ b/lib/technical_analysis/indicators/evm.rb @@ -69,7 +69,7 @@ def self.calculate(data, period: 14) period_values << emv if period_values.size == period - output << EvmValue.new(date_time: v[:date_time], evm: period_values.average) + output << EvmValue.new(date_time: v[:date_time], evm: ArrayHelper.average(period_values)) period_values.shift end diff --git a/lib/technical_analysis/indicators/kc.rb b/lib/technical_analysis/indicators/kc.rb index d655757..6ce3cd6 100644 --- a/lib/technical_analysis/indicators/kc.rb +++ b/lib/technical_analysis/indicators/kc.rb @@ -66,9 +66,9 @@ def self.calculate(data, period: 10) period_values << { typical_price: tp, trading_range: tr } if period_values.size == period - mb = period_values.map { |pv| pv[:typical_price] }.average + mb = ArrayHelper.average(period_values.map { |pv| pv[:typical_price] }) - trading_range_average = period_values.map { |pv| pv[:trading_range] }.average + trading_range_average = ArrayHelper.average(period_values.map { |pv| pv[:trading_range] }) ub = mb + trading_range_average lb = mb - trading_range_average diff --git a/lib/technical_analysis/indicators/obv_mean.rb b/lib/technical_analysis/indicators/obv_mean.rb index 79628f0..6f70fff 100644 --- a/lib/technical_analysis/indicators/obv_mean.rb +++ b/lib/technical_analysis/indicators/obv_mean.rb @@ -77,7 +77,7 @@ def self.calculate(data, period: 10) prior_close = close if obvs.size == period - output << ObvMeanValue.new(date_time: v[:date_time], obv_mean: obvs.average) + output << ObvMeanValue.new(date_time: v[:date_time], obv_mean: ArrayHelper.average(obvs)) obvs.shift end end diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 1c1c7a7..0ee094f 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -71,8 +71,8 @@ def self.calculate(data, period: 14, price_key: :value) if price_changes.size == period if prev_avg.nil? - avg_gain = price_changes.map { |pc| pc.positive? ? pc : 0 }.average - avg_loss = price_changes.map { |pc| pc.negative? ? pc.abs : 0 }.average + 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 diff --git a/lib/technical_analysis/indicators/sr.rb b/lib/technical_analysis/indicators/sr.rb index 1f2c577..6f64f34 100644 --- a/lib/technical_analysis/indicators/sr.rb +++ b/lib/technical_analysis/indicators/sr.rb @@ -75,7 +75,7 @@ def self.calculate(data, period: 14, signal_period: 3) sr_values << sr if sr_values.size == signal_period - signal = sr_values.average + signal = ArrayHelper.average(sr_values) output << SrValue.new( date_time: v[:date_time], diff --git a/lib/technical_analysis/indicators/tsi.rb b/lib/technical_analysis/indicators/tsi.rb index 47a48a8..ad9474b 100644 --- a/lib/technical_analysis/indicators/tsi.rb +++ b/lib/technical_analysis/indicators/tsi.rb @@ -103,8 +103,8 @@ def self.calculate(data, low_period: 13, high_period: 25, price_key: :value) private_class_method def self.process_ema(current_value, data, multiplier, period, store) if store.empty? - value = data.map { |d| d[:value] }.average - abs_value = data.map { |d| d[:abs_value] }.average + value = ArrayHelper.average(data.map { |d| d[:value] }) + abs_value = ArrayHelper.average(data.map { |d| d[:abs_value] }) else prev_value = store.last value = ((multiplier * (current_value[:value] - prev_value[:value])) + prev_value[:value]) From ed1e55900a1621099b28c042b21dde4d69a52212 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:14:16 -0500 Subject: [PATCH 43/84] Update references to standard_deviation --- lib/technical_analysis/indicators/bb.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/bb.rb b/lib/technical_analysis/indicators/bb.rb index c5018c0..3897667 100644 --- a/lib/technical_analysis/indicators/bb.rb +++ b/lib/technical_analysis/indicators/bb.rb @@ -70,7 +70,7 @@ def self.calculate(data, period: 20, standard_deviations: 2, price_key: :value) if period_values.size == period mb = ArrayHelper.average(period_values) - sd = period_values.standard_deviation + sd = ArrayHelper.standard_deviation(period_values) ub = mb + standard_deviations * sd lb = mb - standard_deviations * sd From 9170c21abf62c70109e8b712a47e8dd27026eccd Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:27:13 -0500 Subject: [PATCH 44/84] Create ArrayHelper spec --- spec/helpers/array_helper_spec.rb | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 spec/helpers/array_helper_spec.rb diff --git a/spec/helpers/array_helper_spec.rb b/spec/helpers/array_helper_spec.rb new file mode 100644 index 0000000..cbad4bd --- /dev/null +++ b/spec/helpers/array_helper_spec.rb @@ -0,0 +1,31 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'ArrayHelper' do + array_of_numbers = [1, 3, 5, 7, 9].freeze + + it 'Calculates sum' do + sum = TechnicalAnalysis::ArrayHelper.sum(array_of_numbers) + expect(sum).to eq(25) + end + + it 'Calculates mean' do + mean = TechnicalAnalysis::ArrayHelper.mean(array_of_numbers) + expect(mean).to eq(5) + end + + it 'Calculates average' do + average = TechnicalAnalysis::ArrayHelper.average(array_of_numbers) + expect(average).to eq(5) + end + + it 'Calculates sample_variance' do + sample_variance = TechnicalAnalysis::ArrayHelper.sample_variance(array_of_numbers) + expect(sample_variance).to eq(10.0) + end + + it 'Calculates standard_deviation' do + standard_deviation = TechnicalAnalysis::ArrayHelper.standard_deviation(array_of_numbers) + expect(standard_deviation).to eq(3.1622776601683795) + end +end From 1bd8c28171698fb0b088c84039c4cc8e7e171427 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:27:23 -0500 Subject: [PATCH 45/84] Add validation test for numeric_data --- spec/helpers/validaton_spec.rb | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/helpers/validaton_spec.rb b/spec/helpers/validaton_spec.rb index 0ec3b34..55329b0 100644 --- a/spec/helpers/validaton_spec.rb +++ b/spec/helpers/validaton_spec.rb @@ -15,4 +15,13 @@ expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_format_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end end + + describe "numeric validation" do + input_data = SpecHelper.get_test_data(:close) + + it 'Throws exception for non numeric price data' do + non_numeric_data = input_data.each { |row| row[:close] = row.delete(:close).to_s } + expect { TechnicalAnalysis::Validation.validate_numeric_data(non_numeric_data, :close) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + end end From 5c30377c9bddd8cff1aa1ab27f4d75af551be069 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:29:39 -0500 Subject: [PATCH 46/84] Update references to Validation in module --- spec/technical_analysis/indicators/adi_spec.rb | 2 +- spec/technical_analysis/indicators/adtv_spec.rb | 4 ++-- spec/technical_analysis/indicators/adx_spec.rb | 4 ++-- spec/technical_analysis/indicators/ao_spec.rb | 4 ++-- spec/technical_analysis/indicators/atr_spec.rb | 4 ++-- spec/technical_analysis/indicators/bb_spec.rb | 4 ++-- spec/technical_analysis/indicators/cci_spec.rb | 4 ++-- spec/technical_analysis/indicators/cmf_spec.rb | 4 ++-- spec/technical_analysis/indicators/cr_spec.rb | 4 ++-- spec/technical_analysis/indicators/dc_spec.rb | 4 ++-- spec/technical_analysis/indicators/dlr_spec.rb | 4 ++-- spec/technical_analysis/indicators/dpo_spec.rb | 4 ++-- spec/technical_analysis/indicators/dr_spec.rb | 4 ++-- spec/technical_analysis/indicators/eom_spec.rb | 4 ++-- spec/technical_analysis/indicators/evm_spec.rb | 4 ++-- spec/technical_analysis/indicators/fi_spec.rb | 4 ++-- spec/technical_analysis/indicators/ichimoku_spec.rb | 4 ++-- spec/technical_analysis/indicators/kc_spec.rb | 4 ++-- spec/technical_analysis/indicators/kst_spec.rb | 4 ++-- spec/technical_analysis/indicators/macd_spec.rb | 4 ++-- spec/technical_analysis/indicators/mfi_spec.rb | 4 ++-- spec/technical_analysis/indicators/mi_spec.rb | 4 ++-- spec/technical_analysis/indicators/nvi_spec.rb | 4 ++-- spec/technical_analysis/indicators/obv_mean_spec.rb | 4 ++-- spec/technical_analysis/indicators/obv_spec.rb | 4 ++-- spec/technical_analysis/indicators/rsi_spec.rb | 4 ++-- spec/technical_analysis/indicators/sma_spec.rb | 4 ++-- spec/technical_analysis/indicators/sr_spec.rb | 4 ++-- spec/technical_analysis/indicators/trix_spec.rb | 4 ++-- spec/technical_analysis/indicators/tsi_spec.rb | 4 ++-- spec/technical_analysis/indicators/uo_spec.rb | 4 ++-- spec/technical_analysis/indicators/vi_spec.rb | 4 ++-- spec/technical_analysis/indicators/vpt_spec.rb | 4 ++-- spec/technical_analysis/indicators/wr_spec.rb | 4 ++-- 34 files changed, 67 insertions(+), 67 deletions(-) diff --git a/spec/technical_analysis/indicators/adi_spec.rb b/spec/technical_analysis/indicators/adi_spec.rb index c2d5e66..2480118 100644 --- a/spec/technical_analysis/indicators/adi_spec.rb +++ b/spec/technical_analysis/indicators/adi_spec.rb @@ -104,7 +104,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/adtv_spec.rb b/spec/technical_analysis/indicators/adtv_spec.rb index 5f447cd..d9ef92e 100644 --- a/spec/technical_analysis/indicators/adtv_spec.rb +++ b/spec/technical_analysis/indicators/adtv_spec.rb @@ -60,7 +60,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, volume_key: :volume)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -86,7 +86,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/adx_spec.rb b/spec/technical_analysis/indicators/adx_spec.rb index 4dcab41..c8f5d23 100644 --- a/spec/technical_analysis/indicators/adx_spec.rb +++ b/spec/technical_analysis/indicators/adx_spec.rb @@ -54,7 +54,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -80,7 +80,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/ao_spec.rb b/spec/technical_analysis/indicators/ao_spec.rb index 3e077b9..c101876 100644 --- a/spec/technical_analysis/indicators/ao_spec.rb +++ b/spec/technical_analysis/indicators/ao_spec.rb @@ -48,7 +48,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, long_period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -74,7 +74,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/atr_spec.rb b/spec/technical_analysis/indicators/atr_spec.rb index 39c304e..488ca8f 100644 --- a/spec/technical_analysis/indicators/atr_spec.rb +++ b/spec/technical_analysis/indicators/atr_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/bb_spec.rb b/spec/technical_analysis/indicators/bb_spec.rb index af59d3d..3e3f9eb 100644 --- a/spec/technical_analysis/indicators/bb_spec.rb +++ b/spec/technical_analysis/indicators/bb_spec.rb @@ -62,7 +62,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -88,7 +88,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/cci_spec.rb b/spec/technical_analysis/indicators/cci_spec.rb index c8365a6..6b6c146 100644 --- a/spec/technical_analysis/indicators/cci_spec.rb +++ b/spec/technical_analysis/indicators/cci_spec.rb @@ -62,7 +62,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -88,7 +88,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/cmf_spec.rb b/spec/technical_analysis/indicators/cmf_spec.rb index 949c27a..a0d104e 100644 --- a/spec/technical_analysis/indicators/cmf_spec.rb +++ b/spec/technical_analysis/indicators/cmf_spec.rb @@ -62,7 +62,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -88,7 +88,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/cr_spec.rb b/spec/technical_analysis/indicators/cr_spec.rb index 7e926f1..a996149 100644 --- a/spec/technical_analysis/indicators/cr_spec.rb +++ b/spec/technical_analysis/indicators/cr_spec.rb @@ -81,7 +81,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -107,7 +107,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/dc_spec.rb b/spec/technical_analysis/indicators/dc_spec.rb index d64183e..79c8e12 100644 --- a/spec/technical_analysis/indicators/dc_spec.rb +++ b/spec/technical_analysis/indicators/dc_spec.rb @@ -62,7 +62,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -88,7 +88,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/dlr_spec.rb b/spec/technical_analysis/indicators/dlr_spec.rb index 2f45204..f4453bf 100644 --- a/spec/technical_analysis/indicators/dlr_spec.rb +++ b/spec/technical_analysis/indicators/dlr_spec.rb @@ -81,7 +81,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -107,7 +107,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/dpo_spec.rb b/spec/technical_analysis/indicators/dpo_spec.rb index 56489a7..997c99a 100644 --- a/spec/technical_analysis/indicators/dpo_spec.rb +++ b/spec/technical_analysis/indicators/dpo_spec.rb @@ -52,7 +52,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -78,7 +78,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/dr_spec.rb b/spec/technical_analysis/indicators/dr_spec.rb index 4abdeeb..c360f53 100644 --- a/spec/technical_analysis/indicators/dr_spec.rb +++ b/spec/technical_analysis/indicators/dr_spec.rb @@ -81,7 +81,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([], price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([], price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -107,7 +107,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/eom_spec.rb b/spec/technical_analysis/indicators/eom_spec.rb index 5e2c840..9fb20c1 100644 --- a/spec/technical_analysis/indicators/eom_spec.rb +++ b/spec/technical_analysis/indicators/eom_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb index 9267331..9ac5a38 100644 --- a/spec/technical_analysis/indicators/evm_spec.rb +++ b/spec/technical_analysis/indicators/evm_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/fi_spec.rb b/spec/technical_analysis/indicators/fi_spec.rb index dd9b6c2..850a5e0 100644 --- a/spec/technical_analysis/indicators/fi_spec.rb +++ b/spec/technical_analysis/indicators/fi_spec.rb @@ -80,7 +80,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -106,7 +106,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/ichimoku_spec.rb b/spec/technical_analysis/indicators/ichimoku_spec.rb index 3e308a6..7101a42 100644 --- a/spec/technical_analysis/indicators/ichimoku_spec.rb +++ b/spec/technical_analysis/indicators/ichimoku_spec.rb @@ -57,7 +57,7 @@ high_period = 40 size_limit = (medium_period + high_period + 1) - expect {indicator.calculate(input_data, high_period: size_limit)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, high_period: size_limit)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -83,7 +83,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/kc_spec.rb b/spec/technical_analysis/indicators/kc_spec.rb index 872e612..423002a 100644 --- a/spec/technical_analysis/indicators/kc_spec.rb +++ b/spec/technical_analysis/indicators/kc_spec.rb @@ -72,7 +72,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -98,7 +98,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/kst_spec.rb b/spec/technical_analysis/indicators/kst_spec.rb index b0c83c0..44386fd 100644 --- a/spec/technical_analysis/indicators/kst_spec.rb +++ b/spec/technical_analysis/indicators/kst_spec.rb @@ -40,7 +40,7 @@ it "Throws exception if not enough data" do roc4 = 60 sma4 = 30 - expect {indicator.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, roc4: roc4, sma4: sma4, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -66,7 +66,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/macd_spec.rb b/spec/technical_analysis/indicators/macd_spec.rb index c41cc96..5e79766 100644 --- a/spec/technical_analysis/indicators/macd_spec.rb +++ b/spec/technical_analysis/indicators/macd_spec.rb @@ -48,7 +48,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, slow_period: input_data.size+1, signal_period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -74,7 +74,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/mfi_spec.rb b/spec/technical_analysis/indicators/mfi_spec.rb index 073a9ca..9b46e53 100644 --- a/spec/technical_analysis/indicators/mfi_spec.rb +++ b/spec/technical_analysis/indicators/mfi_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/mi_spec.rb b/spec/technical_analysis/indicators/mi_spec.rb index f41b3c0..37ceec6 100644 --- a/spec/technical_analysis/indicators/mi_spec.rb +++ b/spec/technical_analysis/indicators/mi_spec.rb @@ -41,7 +41,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, ema_period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -67,7 +67,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/nvi_spec.rb b/spec/technical_analysis/indicators/nvi_spec.rb index d200a94..9b63de2 100644 --- a/spec/technical_analysis/indicators/nvi_spec.rb +++ b/spec/technical_analysis/indicators/nvi_spec.rb @@ -81,7 +81,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -107,7 +107,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/obv_mean_spec.rb b/spec/technical_analysis/indicators/obv_mean_spec.rb index 34f386a..d4edd4b 100644 --- a/spec/technical_analysis/indicators/obv_mean_spec.rb +++ b/spec/technical_analysis/indicators/obv_mean_spec.rb @@ -71,7 +71,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -97,7 +97,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/obv_spec.rb b/spec/technical_analysis/indicators/obv_spec.rb index c111ee8..7e9eb98 100644 --- a/spec/technical_analysis/indicators/obv_spec.rb +++ b/spec/technical_analysis/indicators/obv_spec.rb @@ -81,7 +81,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -107,7 +107,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb index 513eab8..9c94836 100644 --- a/spec/technical_analysis/indicators/rsi_spec.rb +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index 47588d7..dc6cbe6 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -77,7 +77,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -103,7 +103,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/sr_spec.rb b/spec/technical_analysis/indicators/sr_spec.rb index 2359158..6621866 100644 --- a/spec/technical_analysis/indicators/sr_spec.rb +++ b/spec/technical_analysis/indicators/sr_spec.rb @@ -66,7 +66,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -92,7 +92,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/trix_spec.rb b/spec/technical_analysis/indicators/trix_spec.rb index 39750ad..33298f1 100644 --- a/spec/technical_analysis/indicators/trix_spec.rb +++ b/spec/technical_analysis/indicators/trix_spec.rb @@ -38,7 +38,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -64,7 +64,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/tsi_spec.rb b/spec/technical_analysis/indicators/tsi_spec.rb index 4fe63ff..4151ae9 100644 --- a/spec/technical_analysis/indicators/tsi_spec.rb +++ b/spec/technical_analysis/indicators/tsi_spec.rb @@ -49,7 +49,7 @@ size_limit = low_period + high_period - 1 input_data = input_data.first(size_limit) - expect {indicator.calculate(input_data, low_period: low_period, high_period: high_period, price_key: :close)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, low_period: low_period, high_period: high_period, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -75,7 +75,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/uo_spec.rb b/spec/technical_analysis/indicators/uo_spec.rb index 61740ae..63b8037 100644 --- a/spec/technical_analysis/indicators/uo_spec.rb +++ b/spec/technical_analysis/indicators/uo_spec.rb @@ -53,7 +53,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, long_period: input_data.size+2)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, long_period: input_data.size+2)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -79,7 +79,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/vi_spec.rb b/spec/technical_analysis/indicators/vi_spec.rb index ea93f29..d85f318 100644 --- a/spec/technical_analysis/indicators/vi_spec.rb +++ b/spec/technical_analysis/indicators/vi_spec.rb @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -93,7 +93,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/vpt_spec.rb b/spec/technical_analysis/indicators/vpt_spec.rb index 0db8506..6ea35e0 100644 --- a/spec/technical_analysis/indicators/vpt_spec.rb +++ b/spec/technical_analysis/indicators/vpt_spec.rb @@ -80,7 +80,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate([])}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -106,7 +106,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do diff --git a/spec/technical_analysis/indicators/wr_spec.rb b/spec/technical_analysis/indicators/wr_spec.rb index 7284fc9..b2317d3 100644 --- a/spec/technical_analysis/indicators/wr_spec.rb +++ b/spec/technical_analysis/indicators/wr_spec.rb @@ -68,7 +68,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+1)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -94,7 +94,7 @@ it 'Throws exception for invalid options' do invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(Validation::ValidationError) + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Calculates minimum data size' do From a135cc8e7f1f0e713023a8d6b484544ca207841d Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 6 Mar 2019 16:44:52 -0500 Subject: [PATCH 47/84] Remove forced use of timestamp format --- lib/technical_analysis/helpers/validation.rb | 10 ++-------- spec/helpers/validaton_spec.rb | 5 ----- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 666610a..68f0639 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -20,15 +20,9 @@ def self.validate_options(options, valid_options) return true if (options.keys - valid_options).empty? raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}" end - + def self.validate_date_time_key(data) - first_data = data.first - - begin - unless first_data.key?(:date_time) && DateTime.parse(first_data[:date_time]) - raise ValidationError.new "Dataset must include date_time field with timestamps" - end - rescue + unless data.all? { |row| row.keys.include? :date_time } raise ValidationError.new "Dataset must include date_time field with timestamps" end end diff --git a/spec/helpers/validaton_spec.rb b/spec/helpers/validaton_spec.rb index 55329b0..8a957f9 100644 --- a/spec/helpers/validaton_spec.rb +++ b/spec/helpers/validaton_spec.rb @@ -9,11 +9,6 @@ bad_date_time_key_data = input_data.each { |row| row[:bad_timestamp_key] = row.delete :date_time } expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_key_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end - - it 'Throws exception for invalid timestamp format' do - bad_date_time_format_data = input_data.each { |row| row[:date_time] = Date.today } - expect { TechnicalAnalysis::Validation.validate_date_time_key(bad_date_time_format_data) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) - end end describe "numeric validation" do From 30622ea9246cf8ca1565b492316024b79f9157af Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:24:48 -0700 Subject: [PATCH 48/84] Removed duplicate --- lib/technical_analysis.rb | 1 - lib/technical_analysis/indicators/evm.rb | 104 ----------------------- 2 files changed, 105 deletions(-) delete mode 100644 lib/technical_analysis/indicators/evm.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index 1925828..1274f34 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -20,7 +20,6 @@ require 'technical_analysis/indicators/dpo' require 'technical_analysis/indicators/dr' require 'technical_analysis/indicators/eom' -require 'technical_analysis/indicators/evm' require 'technical_analysis/indicators/fi' require 'technical_analysis/indicators/ichimoku' require 'technical_analysis/indicators/kc' diff --git a/lib/technical_analysis/indicators/evm.rb b/lib/technical_analysis/indicators/evm.rb deleted file mode 100644 index 2991dfe..0000000 --- a/lib/technical_analysis/indicators/evm.rb +++ /dev/null @@ -1,104 +0,0 @@ -module TechnicalAnalysis - # Ease of Movement - class Evm < Indicator - - # Returns the symbol of the technical indicator - # - # @return [String] A string of the symbol of the technical indicator - def self.indicator_symbol - "evm" - end - - # Returns the name of the technical indicator - # - # @return [String] A string of the name of the technical indicator - def self.indicator_name - "Ease of Movement" - end - - # Returns an array of valid keys for options for this technical indicator - # - # @return [Array] An array of keys as symbols for valid options for this technical indicator - def self.valid_options - %i(period) - end - - # Validates the provided options for this technical indicator - # - # @param options [Hash] The options for the technical indicator to be validated - # - # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not - def self.validate_options(options) - Validation.validate_options(options, valid_options) - end - - # Calculates the minimum number of observations needed to calculate the technical indicator - # - # @param options [Hash] The options for the technical indicator - # - # @return [Integer] Returns the minimum number of observations needed to calculate the technical - # indicator based on the options provided - def self.min_data_size(period: 14) - period.to_i + 1 - end - - # Calculates the ease of movement (EVM) for the data over the given period - # https://en.wikipedia.org/wiki/Ease_of_movement - # - # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :volume) - # @param period [Integer] The given period to calculate the EVM - # - # @return [Array] An array of EvmValue instances - def self.calculate(data, period: 14) - period = period.to_i - Validation.validate_numeric_data(data, :high, :low, :volume) - Validation.validate_length(data, min_data_size(period: period)) - Validation.validate_date_time_key(data) - - data = data.sort_by { |row| row[:date_time] } - - output = [] - period_values = [] - prev_price = data.shift - - data.each do |v| - distance_moved = ((v[:high] + v[:low]) / 2) - ((prev_price[:high] + prev_price[:low]) / 2) - box_ratio = (v[:volume] / 100_000_000.00) / (v[:high] - v[:low]) - emv = distance_moved / box_ratio - - period_values << emv - - if period_values.size == period - output << EvmValue.new(date_time: v[:date_time], evm: ArrayHelper.average(period_values)) - period_values.shift - end - - prev_price = v - end - - output.sort_by(&:date_time).reverse - end - - end - - # The value class to be returned by calculations - class EvmValue - - # @return [String] the date_time of the obversation as it was provided - attr_accessor :date_time - - # @return [Float] the evm calculation value - attr_accessor :evm - - def initialize(date_time: nil, evm: nil) - @date_time = date_time - @evm = evm - end - - # @return [Hash] the attributes as a hash - def to_hash - { date_time: @date_time, evm: @evm } - end - - end -end From 817450ad8e56d3ccbbe5b2c08e715dc681c47ed6 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:25:03 -0700 Subject: [PATCH 49/84] Made Indicator.roster public --- lib/technical_analysis/indicators/indicator.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index b935d1a..a729a07 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -15,7 +15,7 @@ class Indicator # Returns an array of TechnicalAnalysis modules # # @return [Array] A list of TechnicalAnalysis::Class - private_class_method def self.roster + def self.roster [ TechnicalAnalysis::Adi, TechnicalAnalysis::Adtv, @@ -31,7 +31,6 @@ class Indicator TechnicalAnalysis::Dpo, TechnicalAnalysis::Dr, TechnicalAnalysis::Eom, - TechnicalAnalysis::Evm, TechnicalAnalysis::Fi, TechnicalAnalysis::Ichimoku, TechnicalAnalysis::Kc, From bc310bf6db4fc6313117f31042e14de6ed7070e7 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:25:14 -0700 Subject: [PATCH 50/84] Updated README --- README.md | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7e0e18c..20e47bb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,41 @@ # technical-analysis A Ruby library for performing technical analysis on stock prices and other data sets. +## Indicators +The following technical indicators are supported: +- Accumulation/Distribution Index (ADI) +- Average Daily Trading Volume (ADTV) +- Average Directional Index (ADX) +- Awesome Oscillator (AO) +- Average True Range (ATR) +- Bollinger Bands (BB) +- Commodity Channel Index (CCI) +- Chaikin Money Flow (CMF) +- Cumulative Return (CR) +- Donchian Channel (DC) +- Daily Log Return (DLR) +- Detrended Price Oscillator (DPO) +- Daily Return (DR) +- Ease of Movement (EOM) +- Force Index (FI) +- Ichimoku Kinko Hyo (ICHIMOKU) +- Keltner Channel (KC) +- Know Sure Thing (KST) +- Moving Average Convergence Divergence (MACD) +- Money Flow Index (MFI) +- Mass Index (MI) +- Negative Volume Index (NVI) +- On-balance Volume (OBV) +- On-balance Volume Mean (OBV_MEAN) +- Relative Strength Index (RSI) +- Simple Moving Average (SMA) +- Stochastic Oscillator (SR) +- Triple Exponential Average (TRIX) +- True Strength Index (TSI) +- Ultimate Oscillator (UO) +- Vortex Indicator (VI) +- Volume-price Trend (VPT) +- Williams %R (WR) + ## Run Tests -`rspec spec` \ No newline at end of file +`rspec spec` From 0fe6a1106e71860a937ece90fcf78d5b057dc37b Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:25:24 -0700 Subject: [PATCH 51/84] v0.1.0 --- technical-analysis.gemspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index 5d246e2..c22236c 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "1.0.0" + spec.version = "0.1.0" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] spec.description = %q{Intrinio Technical Analysis} @@ -14,4 +14,4 @@ Gem::Specification.new do |spec| spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "yard", "~> 0.9.6" -end \ No newline at end of file +end From 0004a729bb5d7288747a276df521022998c08705 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:25:32 -0700 Subject: [PATCH 52/84] gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5e1422c..39a5d58 100644 --- a/.gitignore +++ b/.gitignore @@ -48,3 +48,4 @@ build-iPhoneSimulator/ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: .rvmrc +.tool-versions From 71f9426006595b97c67fd40a63bfc0d91b24d324 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:28:11 -0700 Subject: [PATCH 53/84] Removed old spec --- .../technical_analysis/indicators/evm_spec.rb | 105 ------------------ 1 file changed, 105 deletions(-) delete mode 100644 spec/technical_analysis/indicators/evm_spec.rb diff --git a/spec/technical_analysis/indicators/evm_spec.rb b/spec/technical_analysis/indicators/evm_spec.rb deleted file mode 100644 index 9ac5a38..0000000 --- a/spec/technical_analysis/indicators/evm_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -require 'technical-analysis' -require 'spec_helper' - -describe 'Indicators' do - describe "EVM" do - input_data = SpecHelper.get_test_data(:high, :low, :volume) - indicator = TechnicalAnalysis::Evm - - describe 'Ease of Movement' do - it 'Calculates EVM (14 day)' do - output = indicator.calculate(input_data, period: 14) - normalized_output = output.map(&:to_hash) - - expected_output = [ - {:date_time=>"2019-01-09T00:00:00.000Z", :evm=>-6.497226050937367}, - {:date_time=>"2019-01-08T00:00:00.000Z", :evm=>-7.7025655861800235}, - {:date_time=>"2019-01-07T00:00:00.000Z", :evm=>-10.852331038262774}, - {:date_time=>"2019-01-04T00:00:00.000Z", :evm=>-13.901372232239117}, - {:date_time=>"2019-01-03T00:00:00.000Z", :evm=>-14.868322149693872}, - {:date_time=>"2019-01-02T00:00:00.000Z", :evm=>-10.542472341445862}, - {:date_time=>"2018-12-31T00:00:00.000Z", :evm=>-7.266128029998595}, - {:date_time=>"2018-12-28T00:00:00.000Z", :evm=>-11.754905920393293}, - {:date_time=>"2018-12-27T00:00:00.000Z", :evm=>-15.149439471732872}, - {:date_time=>"2018-12-26T00:00:00.000Z", :evm=>-21.397258702024285}, - {:date_time=>"2018-12-24T00:00:00.000Z", :evm=>-29.127850557035778}, - {:date_time=>"2018-12-21T00:00:00.000Z", :evm=>-21.640253827328284}, - {:date_time=>"2018-12-20T00:00:00.000Z", :evm=>-19.510117531121228}, - {:date_time=>"2018-12-19T00:00:00.000Z", :evm=>-14.184550665717635}, - {:date_time=>"2018-12-18T00:00:00.000Z", :evm=>-5.583810139052782}, - {:date_time=>"2018-12-17T00:00:00.000Z", :evm=>-5.714363954096145}, - {:date_time=>"2018-12-14T00:00:00.000Z", :evm=>-5.49920090817078}, - {:date_time=>"2018-12-13T00:00:00.000Z", :evm=>-8.427863395925653}, - {:date_time=>"2018-12-12T00:00:00.000Z", :evm=>-8.897024349696329}, - {:date_time=>"2018-12-11T00:00:00.000Z", :evm=>-15.409243349973261}, - {:date_time=>"2018-12-10T00:00:00.000Z", :evm=>-21.68916026908629}, - {:date_time=>"2018-12-07T00:00:00.000Z", :evm=>-15.003602992747133}, - {:date_time=>"2018-12-06T00:00:00.000Z", :evm=>-14.327931101318542}, - {:date_time=>"2018-12-04T00:00:00.000Z", :evm=>-13.565693513893978}, - {:date_time=>"2018-12-03T00:00:00.000Z", :evm=>-11.780616477806618}, - {:date_time=>"2018-11-30T00:00:00.000Z", :evm=>-20.874548142667777}, - {:date_time=>"2018-11-29T00:00:00.000Z", :evm=>-23.304959556064855}, - {:date_time=>"2018-11-28T00:00:00.000Z", :evm=>-23.906907831421474}, - {:date_time=>"2018-11-27T00:00:00.000Z", :evm=>-24.18360420308819}, - {:date_time=>"2018-11-26T00:00:00.000Z", :evm=>-23.02094878061384}, - {:date_time=>"2018-11-23T00:00:00.000Z", :evm=>-27.26817615617346}, - {:date_time=>"2018-11-21T00:00:00.000Z", :evm=>-28.2247053700715}, - {:date_time=>"2018-11-20T00:00:00.000Z", :evm=>-27.37028760395389}, - {:date_time=>"2018-11-19T00:00:00.000Z", :evm=>-16.94506299946587}, - {:date_time=>"2018-11-16T00:00:00.000Z", :evm=>-13.43297156412281}, - {:date_time=>"2018-11-15T00:00:00.000Z", :evm=>-23.978202090280167}, - {:date_time=>"2018-11-14T00:00:00.000Z", :evm=>-26.374761082588922}, - {:date_time=>"2018-11-13T00:00:00.000Z", :evm=>-22.593717509723117}, - {:date_time=>"2018-11-12T00:00:00.000Z", :evm=>-19.69000228424736}, - {:date_time=>"2018-11-09T00:00:00.000Z", :evm=>-16.918604972309158}, - {:date_time=>"2018-11-08T00:00:00.000Z", :evm=>-11.567473480653877}, - {:date_time=>"2018-11-07T00:00:00.000Z", :evm=>-10.367227984759097}, - {:date_time=>"2018-11-06T00:00:00.000Z", :evm=>-22.183583990006944}, - {:date_time=>"2018-11-05T00:00:00.000Z", :evm=>-22.338003197707696}, - {:date_time=>"2018-11-02T00:00:00.000Z", :evm=>-16.2797807192085}, - {:date_time=>"2018-11-01T00:00:00.000Z", :evm=>-10.135395436615527}, - {:date_time=>"2018-10-31T00:00:00.000Z", :evm=>-6.606596973217312}, - {:date_time=>"2018-10-30T00:00:00.000Z", :evm=>-16.275660385464448}, - {:date_time=>"2018-10-29T00:00:00.000Z", :evm=>-21.877975231994814} - ] - - expect(normalized_output).to eq(expected_output) - end - - it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) - end - - it 'Returns the symbol' do - indicator_symbol = indicator.indicator_symbol - expect(indicator_symbol).to eq('evm') - end - - it 'Returns the name' do - indicator_name = indicator.indicator_name - expect(indicator_name).to eq('Ease of Movement') - end - - it 'Returns the valid options' do - valid_options = indicator.valid_options - expect(valid_options).to eq(%i(period)) - end - - it 'Validates options' do - valid_options = { period: 22 } - options_validated = indicator.validate_options(valid_options) - expect(options_validated).to eq(true) - end - - it 'Throws exception for invalid options' do - invalid_options = { test: 10 } - expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) - end - - it 'Calculates minimum data size' do - options = { period: 4 } - expect(indicator.min_data_size(options)).to eq(5) - end - end - end -end From cfabd0b6ec32bc81be832be75f7d86a8b3700693 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:30:41 -0700 Subject: [PATCH 54/84] CircleCI Config --- .circleci/config.yml | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..8106247 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,48 @@ +version: 2 +jobs: + build: + docker: + - image: circleci/ruby:2.3.1 + working_directory: ~/repo + + steps: + - checkout + + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "Gemfile.lock" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + + - run: + name: install dependencies + command: | + bundle install --jobs=4 --retry=3 --path vendor/bundle + + - save_cache: + paths: + - ./vendor/bundle + key: v1-dependencies-{{ checksum "Gemfile.lock" }} + + # run tests! + - run: + name: run tests + command: | + mkdir /tmp/test-results + TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \ + circleci tests split --split-by=timings)" + + bundle exec rspec \ + --format progress \ + --format RspecJunitFormatter \ + --out /tmp/test-results/rspec.xml \ + --format progress \ + $TEST_FILES + + # collect reports + - store_test_results: + path: /tmp/test-results + - store_artifacts: + path: /tmp/test-results + destination: test-results From 2d1d07ece8d111d43bfbb56233aea811ce41fc8a Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:31:47 -0700 Subject: [PATCH 55/84] CircleCI Config --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8106247..c15ba6a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -2,7 +2,7 @@ version: 2 jobs: build: docker: - - image: circleci/ruby:2.3.1 + - image: circleci/ruby:2.3.6 working_directory: ~/repo steps: From 65d9eed13efd417f049e56bfaec9da1de13e2e14 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:33:57 -0700 Subject: [PATCH 56/84] CircleCI Config --- .circleci/config.yml | 58 +++++++++----------------------------------- Gemfile.lock | 37 ++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 46 deletions(-) create mode 100644 Gemfile.lock diff --git a/.circleci/config.yml b/.circleci/config.yml index c15ba6a..6f4f45b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,48 +1,14 @@ version: 2 jobs: - build: - docker: - - image: circleci/ruby:2.3.6 - working_directory: ~/repo - - steps: - - checkout - - # Download and cache dependencies - - restore_cache: - keys: - - v1-dependencies-{{ checksum "Gemfile.lock" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - - - run: - name: install dependencies - command: | - bundle install --jobs=4 --retry=3 --path vendor/bundle - - - save_cache: - paths: - - ./vendor/bundle - key: v1-dependencies-{{ checksum "Gemfile.lock" }} - - # run tests! - - run: - name: run tests - command: | - mkdir /tmp/test-results - TEST_FILES="$(circleci tests glob "spec/**/*_spec.rb" | \ - circleci tests split --split-by=timings)" - - bundle exec rspec \ - --format progress \ - --format RspecJunitFormatter \ - --out /tmp/test-results/rspec.xml \ - --format progress \ - $TEST_FILES - - # collect reports - - store_test_results: - path: /tmp/test-results - - store_artifacts: - path: /tmp/test-results - destination: test-results + build: + working_directory: ~/technical-analysis + docker: + - image: circleci/ruby:2.3.6 + steps: + - checkout + + # Bundle install dependencies + - run: bundle install + + # Run the tests + - run: bundle exec rspec diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..bec5db7 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,37 @@ +PATH + remote: . + specs: + technical-analysis (0.1.0) + +GEM + remote: https://rubygems.org/ + specs: + diff-lcs (1.3) + rake (10.5.0) + rspec (3.8.0) + rspec-core (~> 3.8.0) + rspec-expectations (~> 3.8.0) + rspec-mocks (~> 3.8.0) + rspec-core (3.8.0) + rspec-support (~> 3.8.0) + rspec-expectations (3.8.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-mocks (3.8.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.8.0) + rspec-support (3.8.0) + yard (0.9.18) + +PLATFORMS + ruby + +DEPENDENCIES + bundler (~> 1.16) + rake (~> 10.0) + rspec (~> 3.0) + technical-analysis! + yard (~> 0.9.6) + +BUNDLED WITH + 1.17.1 From fe6c34f1ce8ec029d0b0df01df9456a4a564c35a Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Wed, 6 Mar 2019 16:40:05 -0700 Subject: [PATCH 57/84] Updated gemspec --- technical-analysis.gemspec | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index c22236c..86b1dfe 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,14 +1,14 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "0.1.0" + spec.version = "0.1.1" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] - spec.description = %q{Intrinio Technical Analysis} - spec.summary = %q{Intrinio Technical Analysis} + spec.description = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} + spec.summary = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} spec.homepage = "https://github.com/intrinio/technical-analysis" spec.files = Dir["{spec,lib}/**/*.*"] spec.require_path = "lib" - spec.metadata['allowed_push_host'] = 'https://intrinio.com' + spec.metadata['allowed_push_host'] = 'https://rubygems.org' spec.add_development_dependency "bundler", "~> 1.16" spec.add_development_dependency "rake", "~> 10.0" From 29b9460ce45edfc0f33c5a3df847bd1456c73f25 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 18 Mar 2019 13:26:22 -0400 Subject: [PATCH 58/84] Update README with code samples and more details --- README.md | 118 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) diff --git a/README.md b/README.md index 20e47bb..6c56178 100644 --- a/README.md +++ b/README.md @@ -37,5 +37,123 @@ The following technical indicators are supported: - Volume-price Trend (VPT) - Williams %R (WR) +## Install + +Add the following line to Gemfile: + +```ruby +gem 'technical-analysis' +``` + +and run `bundle install` from your shell. + +To install the gem manually from your shell, run: + +```shell +gem install technical-analysis +``` + +## Usage +There are 2 ways to use this gem for technical analysis. + +First, for the sake of these code samples, we'll load some test data from `spec/ta_test_data.csv`. This is the same data used for the unit tests. The data will be an `Array` of `Hashes`. + +```ruby +input_data = SpecHelper.get_test_data(:close) +# [ +# { date_time: "2019-01-09T00:00:00.000Z", close: 153.3100 }, +# { date_time: "2019-01-08T00:00:00.000Z", close: 150.7500 }, +# ... +# { date_time: "2018-10-09T00:00:00.000Z", close: 226.8700 } +# ] +``` + +### 1) Call the `calculate` method on the specific technical indicator class +```ruby +TechnicalAnalysis::Sma.calculate(input_data, period: 30, price_key: :close) +``` + +### 2) Call the generic indicator class and pass params to the `calculate` method +The calculate method accepts: +- The indicator `symbol` as a String - `"sma"` +- The data to be used for calculations as an Array of Hashes - `input_data` +- The symbol of the calculation to be performed - `:technicals` +- The options for the indicator as a Hash - `options` +```ruby +options = { period: 30, price_key: :close } +TechnicalAnalysis::Indicator.calculate('sma', input_data, :technicals, options) +``` + +Each technical indicator has the following methods: +- `indicator_symbol` returns the symbol of the technical indicator as a String. +- `indicator_name` returns the name of the technical indicator as a String. +- `valid_options` returns an Array of keys (as Symbols) for valid options that the technical indicator accepts in its `calculate` method. +- `validate_options` returns true if the options provided are valid or raises a `ValidationError`. +- `min_data_size` returns the minimum number of observations needed (as an Integer) to calculate the technical indicator based on the options provided. +- `calculate` - Each technical indicator returns an Array of values. These values are instances of a class specific to each indicator. It's typically in the format of SymbolValue. For example, Simple Moving Average (SMA) returns an Array of `SmaValue` instances. These classes contain the appropriate data fields for each technical indicator. + +For example: +```ruby +TechnicalAnalysis::Sma.indicator_symbol +# "sma" + +TechnicalAnalysis::Sma.indicator_name +# "Simple Moving Average" + +TechnicalAnalysis::Sma.valid_options +# [:period, :price_key] + +options = { period: 30, price_key: :close } +TechnicalAnalysis::Sma.validate_options(options) +# true + +options = { period: 30, price_key: :close } +TechnicalAnalysis::Sma.min_data_size(options) +# 30 +``` + +You can also use the generic indicator class. The purpose of this class is to be a sort of master class that will find and call the correct indicator based on the params provided to it. + +Here's each example again using the generic indicator class: +```ruby +input_data = SpecHelper.get_test_data(:close) + +TechnicalAnalysis::Indicator.calculate('sma', input_data, :indicator_symbol) +# "sma" + +TechnicalAnalysis::Indicator.indicator_name('sma', input_data, :indicator_name) +# "Simple Moving Average" + +TechnicalAnalysis::Indicator.valid_options('sma', input_data, :valid_options) +# [:period, :price_key] + +options = { period: 30, price_key: :close } +TechnicalAnalysis::Indicator.validate_options('sma', input_data, :validate_options, options) +# true + +options = { period: 30, price_key: :close } +TechnicalAnalysis::Indicator.min_data_size('sma', input_data, :min_data_size, options) +# 30 +``` + +Or you can use it to find the correct technical indicator class based on symbol: +```ruby +input_data = SpecHelper.get_test_data(:close) + +indicator = TechnicalAnalysis::Indicator.find("sma") +# TechnicalAnalysis::Sma + +indicator.indicator_symbol +# "sma" + +indicator.indicator_name +# "Simple Moving Average" + +indicator.calculate(input_data, period: 30, price_key: :close) +``` + +## Further documentation +This gem is also documented using [Yard](https://yardoc.org/). You can view the [guides](https://yardoc.org/guides/index.html) to help get you started. + ## Run Tests `rspec spec` From c498da050b3fcf4865e3eb49a1b6fef4fbe2f0fd Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 18 Mar 2019 14:38:55 -0400 Subject: [PATCH 59/84] Add Volume Weighted Average Price (VWAP) --- lib/technical_analysis.rb | 1 + .../indicators/indicator.rb | 1 + lib/technical_analysis/indicators/vwap.rb | 97 ++++++++++++++ .../indicators/vwap_spec.rb | 119 ++++++++++++++++++ 4 files changed, 218 insertions(+) create mode 100644 lib/technical_analysis/indicators/vwap.rb create mode 100644 spec/technical_analysis/indicators/vwap_spec.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index 1274f34..67c1aa4 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -38,4 +38,5 @@ require 'technical_analysis/indicators/uo' require 'technical_analysis/indicators/vi' require 'technical_analysis/indicators/vpt' +require 'technical_analysis/indicators/vwap' require 'technical_analysis/indicators/wr' diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index a729a07..585c9b0 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -49,6 +49,7 @@ def self.roster TechnicalAnalysis::Uo, TechnicalAnalysis::Vi, TechnicalAnalysis::Vpt, + TechnicalAnalysis::Vwap, TechnicalAnalysis::Wr, ] end diff --git a/lib/technical_analysis/indicators/vwap.rb b/lib/technical_analysis/indicators/vwap.rb new file mode 100644 index 0000000..a47466f --- /dev/null +++ b/lib/technical_analysis/indicators/vwap.rb @@ -0,0 +1,97 @@ +module TechnicalAnalysis + # Volume Weighted Average Price + class Vwap < Indicator + + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator + def self.indicator_symbol + "vwap" + end + + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator + def self.indicator_name + "Volume Weighted Average Price" + end + + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator + def self.valid_options + [] + end + + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not + def self.validate_options(options) + return true if options == {} + raise Validation::ValidationError.new "This indicator doesn't accept any options." + end + + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided + def self.min_data_size(**params) + 1 + end + + # Calculates the volume weighted average price (VWAP) for the data + # https://en.wikipedia.org/wiki/Volume-weighted_average_price + # + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # + # @return [Array] An array of VwapValue instances + def self.calculate(data) + Validation.validate_numeric_data(data, :high, :low, :close, :volume) + Validation.validate_length(data, min_data_size) + Validation.validate_date_time_key(data) + + data = data.sort_by { |row| row[:date_time] } + + output = [] + cumm_volume = 0 + cumm_volume_x_typical_price = 0 + + data.each do |v| + typical_price = StockCalculation.typical_price(v) + cumm_volume_x_typical_price += v[:volume] * typical_price + cumm_volume += v[:volume] + vwap = cumm_volume_x_typical_price.to_f / cumm_volume.to_f + + output << VwapValue.new(date_time: v[:date_time], vwap: vwap) + end + + output.sort_by(&:date_time).reverse + end + + end + + # The value class to be returned by calculations + class VwapValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the vwap calculation value + attr_accessor :vwap + + def initialize(date_time: nil, vwap: nil) + @date_time = date_time + @vwap = vwap + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, vwap: @vwap } + end + + end +end diff --git a/spec/technical_analysis/indicators/vwap_spec.rb b/spec/technical_analysis/indicators/vwap_spec.rb new file mode 100644 index 0000000..73e834b --- /dev/null +++ b/spec/technical_analysis/indicators/vwap_spec.rb @@ -0,0 +1,119 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "VWAP" do + input_data = SpecHelper.get_test_data(:volume, :high, :low, :close) + indicator = TechnicalAnalysis::Vwap + + describe 'Volume Weighted Average Price' do + it 'Calculates VWAP' do + output = indicator.calculate(input_data) + normalized_output = output.map(&:to_hash) + + expected_output = [ + {:date_time=>"2019-01-09T00:00:00.000Z", :vwap=>183.55426863053765}, + {:date_time=>"2019-01-08T00:00:00.000Z", :vwap=>184.06635227887782}, + {:date_time=>"2019-01-07T00:00:00.000Z", :vwap=>184.57507590747517}, + {:date_time=>"2019-01-04T00:00:00.000Z", :vwap=>185.3413093796368}, + {:date_time=>"2019-01-03T00:00:00.000Z", :vwap=>186.19781421865375}, + {:date_time=>"2019-01-02T00:00:00.000Z", :vwap=>187.76843731172002}, + {:date_time=>"2018-12-31T00:00:00.000Z", :vwap=>188.21552447966795}, + {:date_time=>"2018-12-28T00:00:00.000Z", :vwap=>188.64862275471472}, + {:date_time=>"2018-12-27T00:00:00.000Z", :vwap=>189.2144975598256}, + {:date_time=>"2018-12-26T00:00:00.000Z", :vwap=>189.9889456493791}, + {:date_time=>"2018-12-24T00:00:00.000Z", :vwap=>190.91953458787302}, + {:date_time=>"2018-12-21T00:00:00.000Z", :vwap=>191.6297166885398}, + {:date_time=>"2018-12-20T00:00:00.000Z", :vwap=>193.36567531270202}, + {:date_time=>"2018-12-19T00:00:00.000Z", :vwap=>194.463693818502}, + {:date_time=>"2018-12-18T00:00:00.000Z", :vwap=>195.21670632642397}, + {:date_time=>"2018-12-17T00:00:00.000Z", :vwap=>195.7127882800064}, + {:date_time=>"2018-12-14T00:00:00.000Z", :vwap=>196.3956319251192}, + {:date_time=>"2018-12-13T00:00:00.000Z", :vwap=>197.03092567150182}, + {:date_time=>"2018-12-12T00:00:00.000Z", :vwap=>197.47196479514173}, + {:date_time=>"2018-12-11T00:00:00.000Z", :vwap=>198.00221355940155}, + {:date_time=>"2018-12-10T00:00:00.000Z", :vwap=>198.7429667210245}, + {:date_time=>"2018-12-07T00:00:00.000Z", :vwap=>199.85255982037654}, + {:date_time=>"2018-12-06T00:00:00.000Z", :vwap=>200.57927838438474}, + {:date_time=>"2018-12-04T00:00:00.000Z", :vwap=>201.28731920049952}, + {:date_time=>"2018-12-03T00:00:00.000Z", :vwap=>201.8731568533139}, + {:date_time=>"2018-11-30T00:00:00.000Z", :vwap=>202.34554208942396}, + {:date_time=>"2018-11-29T00:00:00.000Z", :vwap=>202.95867828112358}, + {:date_time=>"2018-11-28T00:00:00.000Z", :vwap=>203.60135199869035}, + {:date_time=>"2018-11-27T00:00:00.000Z", :vwap=>204.38651817163168}, + {:date_time=>"2018-11-26T00:00:00.000Z", :vwap=>205.30361785858756}, + {:date_time=>"2018-11-23T00:00:00.000Z", :vwap=>206.36274937523916}, + {:date_time=>"2018-11-21T00:00:00.000Z", :vwap=>206.94494917055295}, + {:date_time=>"2018-11-20T00:00:00.000Z", :vwap=>207.6427516507437}, + {:date_time=>"2018-11-19T00:00:00.000Z", :vwap=>209.27699957144853}, + {:date_time=>"2018-11-16T00:00:00.000Z", :vwap=>210.05211892678065}, + {:date_time=>"2018-11-15T00:00:00.000Z", :vwap=>210.59952347188045}, + {:date_time=>"2018-11-14T00:00:00.000Z", :vwap=>211.4589551886514}, + {:date_time=>"2018-11-13T00:00:00.000Z", :vwap=>212.75803369499064}, + {:date_time=>"2018-11-12T00:00:00.000Z", :vwap=>213.6551619737374}, + {:date_time=>"2018-11-09T00:00:00.000Z", :vwap=>214.61043573066618}, + {:date_time=>"2018-11-08T00:00:00.000Z", :vwap=>215.00076838969952}, + {:date_time=>"2018-11-07T00:00:00.000Z", :vwap=>215.18761540540189}, + {:date_time=>"2018-11-06T00:00:00.000Z", :vwap=>215.4663555747261}, + {:date_time=>"2018-11-05T00:00:00.000Z", :vwap=>215.93354729003553}, + {:date_time=>"2018-11-02T00:00:00.000Z", :vwap=>217.20680955786048}, + {:date_time=>"2018-11-01T00:00:00.000Z", :vwap=>218.35223508156088}, + {:date_time=>"2018-10-31T00:00:00.000Z", :vwap=>218.1692825392702}, + {:date_time=>"2018-10-30T00:00:00.000Z", :vwap=>218.13783195840017}, + {:date_time=>"2018-10-29T00:00:00.000Z", :vwap=>218.5155747290589}, + {:date_time=>"2018-10-26T00:00:00.000Z", :vwap=>219.05970452474796}, + {:date_time=>"2018-10-25T00:00:00.000Z", :vwap=>219.3440526461074}, + {:date_time=>"2018-10-24T00:00:00.000Z", :vwap=>219.34643675779574}, + {:date_time=>"2018-10-23T00:00:00.000Z", :vwap=>219.4951598586493}, + {:date_time=>"2018-10-22T00:00:00.000Z", :vwap=>219.41092910048724}, + {:date_time=>"2018-10-19T00:00:00.000Z", :vwap=>219.26375336145847}, + {:date_time=>"2018-10-18T00:00:00.000Z", :vwap=>219.25541442468506}, + {:date_time=>"2018-10-17T00:00:00.000Z", :vwap=>219.65735634491844}, + {:date_time=>"2018-10-16T00:00:00.000Z", :vwap=>219.5125052055069}, + {:date_time=>"2018-10-15T00:00:00.000Z", :vwap=>219.34283327445593}, + {:date_time=>"2018-10-12T00:00:00.000Z", :vwap=>219.44169580294155}, + {:date_time=>"2018-10-11T00:00:00.000Z", :vwap=>219.0592293697168}, + {:date_time=>"2018-10-10T00:00:00.000Z", :vwap=>221.89869420553177}, + {:date_time=>"2018-10-09T00:00:00.000Z", :vwap=>225.4620666666667} + ] + + expect(normalized_output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {indicator.calculate([])}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('vwap') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Volume Weighted Average Price') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq([]) + end + + it 'Validates options' do + valid_options = {} + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = {} + expect(indicator.min_data_size(options)).to eq(1) + end + end + end +end From 01a3ce03cbf5a60247d05aa3fe4edcf6e111c7aa Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 18 Mar 2019 17:17:25 -0400 Subject: [PATCH 60/84] README updates for Indicator class --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6c56178..e07454a 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ TechnicalAnalysis::Sma.calculate(input_data, period: 30, price_key: :close) ``` ### 2) Call the generic indicator class and pass params to the `calculate` method -The calculate method accepts: +The `calculate` method on the `Indicator` class accepts: - The indicator `symbol` as a String - `"sma"` - The data to be used for calculations as an Array of Hashes - `input_data` - The symbol of the calculation to be performed - `:technicals` From 4b9f17a80e3223d85fbd98c1d127e12c375ef6f0 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 18 Mar 2019 17:20:11 -0400 Subject: [PATCH 61/84] Add volume to Yard doc comment --- lib/technical_analysis/indicators/vwap.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/vwap.rb b/lib/technical_analysis/indicators/vwap.rb index a47466f..24c3f5b 100644 --- a/lib/technical_analysis/indicators/vwap.rb +++ b/lib/technical_analysis/indicators/vwap.rb @@ -46,7 +46,7 @@ def self.min_data_size(**params) # Calculates the volume weighted average price (VWAP) for the data # https://en.wikipedia.org/wiki/Volume-weighted_average_price # - # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close) + # @param data [Array] Array of hashes with keys (:date_time, :high, :low, :close, :volume) # # @return [Array] An array of VwapValue instances def self.calculate(data) From 80edbd664be1e3ad72fb2eae524443beeb9299c3 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 19 Mar 2019 10:44:35 -0400 Subject: [PATCH 62/84] More README updates, break usage into 2 sections --- README.md | 80 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index e07454a..57abcac 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,6 @@ gem install technical-analysis ``` ## Usage -There are 2 ways to use this gem for technical analysis. - First, for the sake of these code samples, we'll load some test data from `spec/ta_test_data.csv`. This is the same data used for the unit tests. The data will be an `Array` of `Hashes`. ```ruby @@ -68,31 +66,25 @@ input_data = SpecHelper.get_test_data(:close) # ] ``` -### 1) Call the `calculate` method on the specific technical indicator class -```ruby -TechnicalAnalysis::Sma.calculate(input_data, period: 30, price_key: :close) -``` - -### 2) Call the generic indicator class and pass params to the `calculate` method -The `calculate` method on the `Indicator` class accepts: -- The indicator `symbol` as a String - `"sma"` -- The data to be used for calculations as an Array of Hashes - `input_data` -- The symbol of the calculation to be performed - `:technicals` -- The options for the indicator as a Hash - `options` -```ruby -options = { period: 30, price_key: :close } -TechnicalAnalysis::Indicator.calculate('sma', input_data, :technicals, options) -``` - Each technical indicator has the following methods: +- `calculate` - Each technical indicator returns an Array of values. These values are instances of a class specific to each indicator. It's typically in the format of SymbolValue. For example, Simple Moving Average (SMA) returns an Array of `SmaValue` instances. These classes contain the appropriate data fields for each technical indicator. - `indicator_symbol` returns the symbol of the technical indicator as a String. - `indicator_name` returns the name of the technical indicator as a String. - `valid_options` returns an Array of keys (as Symbols) for valid options that the technical indicator accepts in its `calculate` method. - `validate_options` returns true if the options provided are valid or raises a `ValidationError`. - `min_data_size` returns the minimum number of observations needed (as an Integer) to calculate the technical indicator based on the options provided. -- `calculate` - Each technical indicator returns an Array of values. These values are instances of a class specific to each indicator. It's typically in the format of SymbolValue. For example, Simple Moving Average (SMA) returns an Array of `SmaValue` instances. These classes contain the appropriate data fields for each technical indicator. -For example: +### Class-Based Usage +You can call methods on the class of the specific technical indicator that you want to calculate. To calculate a Simple Moving Average, for example, you would just call `calculate` on the Simple Moving Average class like so: + +```ruby +input_data = SpecHelper.get_test_data(:close) + +TechnicalAnalysis::Sma.calculate(input_data, period: 30, price_key: :close) +``` + +Here are examples of other methods for technical indicators: + ```ruby TechnicalAnalysis::Sma.indicator_symbol # "sma" @@ -112,44 +104,70 @@ TechnicalAnalysis::Sma.min_data_size(options) # 30 ``` +### Generic Usage You can also use the generic indicator class. The purpose of this class is to be a sort of master class that will find and call the correct indicator based on the params provided to it. +The `calculate` method on the `Indicator` class accepts: +- The indicator symbol as a String - `"sma"` +- The data to be used for calculations as an Array of Hashes - `input_data` +- The calculation to be performed as a Symbol - `:technicals` +- The options for the indicator as a Hash - `options` + +```ruby +input_data = SpecHelper.get_test_data(:close) +options = { period: 30, price_key: :close } + +TechnicalAnalysis::Indicator.calculate('sma', input_data, :technicals, options) +``` + Here's each example again using the generic indicator class: + ```ruby input_data = SpecHelper.get_test_data(:close) TechnicalAnalysis::Indicator.calculate('sma', input_data, :indicator_symbol) # "sma" -TechnicalAnalysis::Indicator.indicator_name('sma', input_data, :indicator_name) +TechnicalAnalysis::Indicator.calculate('sma', input_data, :indicator_name) # "Simple Moving Average" -TechnicalAnalysis::Indicator.valid_options('sma', input_data, :valid_options) +TechnicalAnalysis::Indicator.calculate('sma', input_data, :valid_options) # [:period, :price_key] options = { period: 30, price_key: :close } -TechnicalAnalysis::Indicator.validate_options('sma', input_data, :validate_options, options) +TechnicalAnalysis::Indicator.calculate('sma', input_data, :validate_options, options) # true options = { period: 30, price_key: :close } -TechnicalAnalysis::Indicator.min_data_size('sma', input_data, :min_data_size, options) +TechnicalAnalysis::Indicator.calculate('sma', input_data, :min_data_size, options) # 30 ``` -Or you can use it to find the correct technical indicator class based on symbol: -```ruby -input_data = SpecHelper.get_test_data(:close) +Or you can use it to find the correct technical indicator class based on indicator symbol: -indicator = TechnicalAnalysis::Indicator.find("sma") +```ruby +simple_moving_average = TechnicalAnalysis::Indicator.find("sma") # TechnicalAnalysis::Sma -indicator.indicator_symbol +input_data = SpecHelper.get_test_data(:close) +simple_moving_average.calculate(input_data, period: 30, price_key: :close) + +simple_moving_average.indicator_symbol # "sma" -indicator.indicator_name +simple_moving_average.indicator_name # "Simple Moving Average" -indicator.calculate(input_data, period: 30, price_key: :close) +simple_moving_average.valid_options +# [:period, :price_key] + +options = { period: 30, price_key: :close } +simple_moving_average.validate_options(options) +# true + +options = { period: 30, price_key: :close } +simple_moving_average.min_data_size(options) +# 30 ``` ## Further documentation From 89220b7906e12468c0e49670b30816a9d2f7a4c1 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 19 Mar 2019 10:47:14 -0400 Subject: [PATCH 63/84] Add VWAP to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20e47bb..d927316 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ The following technical indicators are supported: - Ultimate Oscillator (UO) - Vortex Indicator (VI) - Volume-price Trend (VPT) +- Volume Weighted Average Price (VWAP) - Williams %R (WR) ## Run Tests From ffd9b120d8c4a749df4b77c9e6c74cc86723b3f5 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Tue, 19 Mar 2019 10:00:54 -0600 Subject: [PATCH 64/84] version --- technical-analysis.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index 86b1dfe..54d9667 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "0.1.1" + spec.version = "0.2.0" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] spec.description = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} From ad1707506e07b86d37b9bb41ca4c58dd5cb2bae1 Mon Sep 17 00:00:00 2001 From: Nick Pellant Date: Wed, 26 Feb 2020 18:17:22 +0000 Subject: [PATCH 65/84] Add EMA indicator I've based the EMA indicator from the SMA indicator, while using the existing `StockCalculation.ema` helper that I found. --- Gemfile.lock | 4 +- README.md | 1 + lib/technical_analysis.rb | 1 + lib/technical_analysis/indicators/ema.rb | 101 +++++++++++++++ .../technical_analysis/indicators/ema_spec.rb | 115 ++++++++++++++++++ 5 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 lib/technical_analysis/indicators/ema.rb create mode 100644 spec/technical_analysis/indicators/ema_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index bec5db7..0e40215 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - technical-analysis (0.1.0) + technical-analysis (0.2.0) GEM remote: https://rubygems.org/ @@ -34,4 +34,4 @@ DEPENDENCIES yard (~> 0.9.6) BUNDLED WITH - 1.17.1 + 1.17.2 diff --git a/README.md b/README.md index 3110acd..d7b2c37 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ The following technical indicators are supported: - Detrended Price Oscillator (DPO) - Daily Return (DR) - Ease of Movement (EOM) +- Exponential Moving Average (EMA) - Force Index (FI) - Ichimoku Kinko Hyo (ICHIMOKU) - Keltner Channel (KC) diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index 67c1aa4..f4368e8 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -19,6 +19,7 @@ require 'technical_analysis/indicators/dlr' require 'technical_analysis/indicators/dpo' require 'technical_analysis/indicators/dr' +require 'technical_analysis/indicators/ema' require 'technical_analysis/indicators/eom' require 'technical_analysis/indicators/fi' require 'technical_analysis/indicators/ichimoku' diff --git a/lib/technical_analysis/indicators/ema.rb b/lib/technical_analysis/indicators/ema.rb new file mode 100644 index 0000000..392d440 --- /dev/null +++ b/lib/technical_analysis/indicators/ema.rb @@ -0,0 +1,101 @@ +module TechnicalAnalysis + # Exponential Moving Average + class Ema < Indicator + + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator + def self.indicator_symbol + "ema" + end + + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator + def self.indicator_name + "Exponential Moving Average" + end + + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator + def self.valid_options + %i(period price_key) + end + + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided + def self.min_data_size(period: 30, **params) + period.to_i + end + + # Calculates the exponential moving average (EMA) for the data over the given period + # https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the EMA + # @param price_key [Symbol] The hash key for the price data. Default :value + # + # @return [Array] An array of EmaValue instances + def self.calculate(data, period: 30, 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] } + + output = [] + period_values = [] + previous_ema = nil + + data.each do |v| + period_values << v[price_key] + if period_values.size == period + ema = StockCalculation.ema(v[price_key], period_values, period, previous_ema) + previous_ema = ema + + output << EmaValue.new(date_time: v[:date_time], ema: ema) + period_values.shift + end + end + + output.sort_by(&:date_time).reverse + end + + end + + # The value class to be returned by calculations + class EmaValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the ema calculation value + attr_accessor :ema + + def initialize(date_time: nil, ema: nil) + @date_time = date_time + @ema = ema + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, ema: @ema } + end + end +end diff --git a/spec/technical_analysis/indicators/ema_spec.rb b/spec/technical_analysis/indicators/ema_spec.rb new file mode 100644 index 0000000..40e2d3b --- /dev/null +++ b/spec/technical_analysis/indicators/ema_spec.rb @@ -0,0 +1,115 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "EMA" do + input_data = SpecHelper.get_test_data(:close) + indicator = TechnicalAnalysis::Ema + + describe 'Exponential Moving Average' do + it 'Calculates EMA (5 day)' do + output = indicator.calculate(input_data, period: 5, price_key: :close) + normalized_output = output.map(&:to_hash) + + expected_output = [ + {:date_time=>"2019-01-09T00:00:00.000Z", :ema=>151.1937160522574}, + {:date_time=>"2019-01-08T00:00:00.000Z", :ema=>150.1355740783861}, + {:date_time=>"2019-01-07T00:00:00.000Z", :ema=>149.82836111757913}, + {:date_time=>"2019-01-04T00:00:00.000Z", :ema=>150.77754167636868}, + {:date_time=>"2019-01-03T00:00:00.000Z", :ema=>152.03631251455303}, + {:date_time=>"2019-01-02T00:00:00.000Z", :ema=>156.95946877182956}, + {:date_time=>"2018-12-31T00:00:00.000Z", :ema=>156.47920315774434}, + {:date_time=>"2018-12-28T00:00:00.000Z", :ema=>155.8488047366165}, + {:date_time=>"2018-12-27T00:00:00.000Z", :ema=>155.65820710492477}, + {:date_time=>"2018-12-26T00:00:00.000Z", :ema=>155.41231065738714}, + {:date_time=>"2018-12-24T00:00:00.000Z", :ema=>154.53346598608073}, + {:date_time=>"2018-12-21T00:00:00.000Z", :ema=>158.3851989791211}, + {:date_time=>"2018-12-20T00:00:00.000Z", :ema=>162.21279846868165}, + {:date_time=>"2018-12-19T00:00:00.000Z", :ema=>164.90419770302248}, + {:date_time=>"2018-12-18T00:00:00.000Z", :ema=>166.91129655453372}, + {:date_time=>"2018-12-17T00:00:00.000Z", :ema=>167.3319448318006}, + {:date_time=>"2018-12-14T00:00:00.000Z", :ema=>169.02791724770088}, + {:date_time=>"2018-12-13T00:00:00.000Z", :ema=>170.80187587155132}, + {:date_time=>"2018-12-12T00:00:00.000Z", :ema=>170.72781380732698}, + {:date_time=>"2018-12-11T00:00:00.000Z", :ema=>171.54172071099046}, + {:date_time=>"2018-12-10T00:00:00.000Z", :ema=>172.99758106648568}, + {:date_time=>"2018-12-07T00:00:00.000Z", :ema=>174.69637159972854}, + {:date_time=>"2018-12-06T00:00:00.000Z", :ema=>177.7995573995928}, + {:date_time=>"2018-12-04T00:00:00.000Z", :ema=>179.33933609938921}, + {:date_time=>"2018-12-03T00:00:00.000Z", :ema=>180.6640041490838}, + {:date_time=>"2018-11-30T00:00:00.000Z", :ema=>178.58600622362573}, + {:date_time=>"2018-11-29T00:00:00.000Z", :ema=>178.5890093354386}, + {:date_time=>"2018-11-28T00:00:00.000Z", :ema=>178.10851400315786}, + {:date_time=>"2018-11-27T00:00:00.000Z", :ema=>176.69277100473678}, + {:date_time=>"2018-11-26T00:00:00.000Z", :ema=>177.91915650710516}, + {:date_time=>"2018-11-23T00:00:00.000Z", :ema=>179.56873476065772}, + {:date_time=>"2018-11-21T00:00:00.000Z", :ema=>183.20810214098657}, + {:date_time=>"2018-11-20T00:00:00.000Z", :ema=>186.42215321147984}, + {:date_time=>"2018-11-19T00:00:00.000Z", :ema=>191.14322981721975}, + {:date_time=>"2018-11-16T00:00:00.000Z", :ema=>193.7848447258296}, + {:date_time=>"2018-11-15T00:00:00.000Z", :ema=>193.9122670887444}, + {:date_time=>"2018-11-14T00:00:00.000Z", :ema=>195.1634006331166}, + {:date_time=>"2018-11-13T00:00:00.000Z", :ema=>199.34510094967487}, + {:date_time=>"2018-11-12T00:00:00.000Z", :ema=>202.90265142451233}, + {:date_time=>"2018-11-09T00:00:00.000Z", :ema=>207.26897713676848}, + {:date_time=>"2018-11-08T00:00:00.000Z", :ema=>208.66846570515273}, + {:date_time=>"2018-11-07T00:00:00.000Z", :ema=>208.75769855772907}, + {:date_time=>"2018-11-06T00:00:00.000Z", :ema=>208.16154783659363}, + {:date_time=>"2018-11-05T00:00:00.000Z", :ema=>210.35732175489045}, + {:date_time=>"2018-11-02T00:00:00.000Z", :ema=>214.7409826323357}, + {:date_time=>"2018-11-01T00:00:00.000Z", :ema=>218.37147394850354}, + {:date_time=>"2018-10-31T00:00:00.000Z", :ema=>216.44721092275532}, + {:date_time=>"2018-10-30T00:00:00.000Z", :ema=>215.24081638413296}, + {:date_time=>"2018-10-29T00:00:00.000Z", :ema=>216.21122457619944}, + {:date_time=>"2018-10-26T00:00:00.000Z", :ema=>218.19683686429914}, + {:date_time=>"2018-10-25T00:00:00.000Z", :ema=>219.1452552964487}, + {:date_time=>"2018-10-24T00:00:00.000Z", :ema=>218.81788294467307}, + {:date_time=>"2018-10-23T00:00:00.000Z", :ema=>220.6818244170096}, + {:date_time=>"2018-10-22T00:00:00.000Z", :ema=>219.65773662551442}, + {:date_time=>"2018-10-19T00:00:00.000Z", :ema=>219.1616049382716}, + {:date_time=>"2018-10-18T00:00:00.000Z", :ema=>219.0874074074074}, + {:date_time=>"2018-10-17T00:00:00.000Z", :ema=>220.6211111111111}, + {:date_time=>"2018-10-16T00:00:00.000Z", :ema=>220.33666666666667}, + {:date_time=>"2018-10-15T00:00:00.000Z", :ema=>219.43} + ] + + expect(normalized_output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('ema') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Exponential Moving Average') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(options)).to eq(4) + end + end + end +end From 7620c8b9cede04cf61558a8be581810d3218b34c Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Thu, 27 Feb 2020 12:29:47 -0700 Subject: [PATCH 66/84] updated yard --- Gemfile.lock | 6 +++--- technical-analysis.gemspec | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index bec5db7..288c661 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - technical-analysis (0.1.0) + technical-analysis (0.2.0) GEM remote: https://rubygems.org/ @@ -21,7 +21,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.8.0) rspec-support (3.8.0) - yard (0.9.18) + yard (0.9.24) PLATFORMS ruby @@ -31,7 +31,7 @@ DEPENDENCIES rake (~> 10.0) rspec (~> 3.0) technical-analysis! - yard (~> 0.9.6) + yard (~> 0.9.20) BUNDLED WITH 1.17.1 diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index 54d9667..33b86b1 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -13,5 +13,5 @@ Gem::Specification.new do |spec| spec.add_development_dependency "bundler", "~> 1.16" spec.add_development_dependency "rake", "~> 10.0" spec.add_development_dependency "rspec", "~> 3.0" - spec.add_development_dependency "yard", "~> 0.9.6" + spec.add_development_dependency "yard", "~> 0.9.20" end From 210598adea7c710f1630004bb2d8ef5dd0773a64 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Thu, 27 Feb 2020 12:32:59 -0700 Subject: [PATCH 67/84] 0.2.1 --- Gemfile.lock | 24 ++++++++++++------------ technical-analysis.gemspec | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 574dab2..f7cbf7c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,26 +1,26 @@ PATH remote: . specs: - technical-analysis (0.2.0) + technical-analysis (0.2.1) GEM remote: https://rubygems.org/ specs: diff-lcs (1.3) rake (10.5.0) - rspec (3.8.0) - rspec-core (~> 3.8.0) - rspec-expectations (~> 3.8.0) - rspec-mocks (~> 3.8.0) - rspec-core (3.8.0) - rspec-support (~> 3.8.0) - rspec-expectations (3.8.2) + rspec (3.9.0) + rspec-core (~> 3.9.0) + rspec-expectations (~> 3.9.0) + rspec-mocks (~> 3.9.0) + rspec-core (3.9.1) + rspec-support (~> 3.9.1) + rspec-expectations (3.9.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-mocks (3.8.0) + rspec-support (~> 3.9.0) + rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.8.0) - rspec-support (3.8.0) + rspec-support (~> 3.9.0) + rspec-support (3.9.2) yard (0.9.24) PLATFORMS diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index 33b86b1..565f3a9 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "0.2.0" + spec.version = "0.2.1" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] spec.description = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} From fa64a6f36393d65ad2a5bce292bdf46c29ab1aa7 Mon Sep 17 00:00:00 2001 From: Nick Pellant Date: Sat, 29 Feb 2020 14:35:49 +0000 Subject: [PATCH 68/84] Add date_time_key support to EMA indicator --- lib/technical_analysis/helpers/validation.rb | 8 ++++---- lib/technical_analysis/indicators/ema.rb | 12 +++++++----- spec/spec_helper.rb | 4 ++-- spec/technical_analysis/indicators/ema_spec.rb | 8 ++++---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/technical_analysis/helpers/validation.rb b/lib/technical_analysis/helpers/validation.rb index 68f0639..a8f8338 100644 --- a/lib/technical_analysis/helpers/validation.rb +++ b/lib/technical_analysis/helpers/validation.rb @@ -20,10 +20,10 @@ def self.validate_options(options, valid_options) return true if (options.keys - valid_options).empty? raise ValidationError.new "Invalid options provided. Valid options are #{valid_options.join(", ")}" end - - def self.validate_date_time_key(data) - unless data.all? { |row| row.keys.include? :date_time } - raise ValidationError.new "Dataset must include date_time field with timestamps" + + def self.validate_date_time_key(data, date_time_key=:date_time) + unless data.all? { |row| row.keys.include? date_time_key } + raise ValidationError.new "Dataset must include '#{date_time_key}' field with timestamps" end end diff --git a/lib/technical_analysis/indicators/ema.rb b/lib/technical_analysis/indicators/ema.rb index 392d440..425c3b1 100644 --- a/lib/technical_analysis/indicators/ema.rb +++ b/lib/technical_analysis/indicators/ema.rb @@ -20,7 +20,7 @@ def self.indicator_name # # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options - %i(period price_key) + %i(period price_key date_time_key) end # Validates the provided options for this technical indicator @@ -48,16 +48,18 @@ def self.min_data_size(period: 30, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the EMA # @param price_key [Symbol] The hash key for the price data. Default :value + # @param date_time_key [Symbol] The hash key for the date time data. Default :date_time # # @return [Array] An array of EmaValue instances - def self.calculate(data, period: 30, price_key: :value) + def self.calculate(data, period: 30, price_key: :value, date_time_key: :date_time) period = period.to_i price_key = price_key.to_sym + date_time_key = date_time_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) + Validation.validate_date_time_key(data, date_time_key) - data = data.sort_by { |row| row[:date_time] } + data = data.sort_by { |row| row[date_time_key] } output = [] period_values = [] @@ -69,7 +71,7 @@ def self.calculate(data, period: 30, price_key: :value) ema = StockCalculation.ema(v[price_key], period_values, period, previous_ema) previous_ema = ema - output << EmaValue.new(date_time: v[:date_time], ema: ema) + output << EmaValue.new(date_time: v[date_time_key], ema: ema) period_values.shift end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ff4e025..0cda646 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,12 +6,12 @@ class SpecHelper FLOAT_KEYS = [:open, :high, :low, :close].freeze INTEGER_KEYS = [:volume].freeze - def self.get_test_data(*columns) + def self.get_test_data(*columns, date_time_key: :date_time) @data = CSV.read(TEST_DATA_PATH, headers: true) columns = columns.map(&:to_sym) output = [] @data.each do |v| - col_hash = { date_time: v["date_time"] } + col_hash = { date_time_key => v["date_time"] } columns.each do |col| value = v[col.to_s] value = value.to_f if FLOAT_KEYS.include?(col) diff --git a/spec/technical_analysis/indicators/ema_spec.rb b/spec/technical_analysis/indicators/ema_spec.rb index 40e2d3b..15da40a 100644 --- a/spec/technical_analysis/indicators/ema_spec.rb +++ b/spec/technical_analysis/indicators/ema_spec.rb @@ -3,12 +3,12 @@ describe 'Indicators' do describe "EMA" do - input_data = SpecHelper.get_test_data(:close) + input_data = SpecHelper.get_test_data(:close, date_time_key: :timestep) indicator = TechnicalAnalysis::Ema describe 'Exponential Moving Average' do it 'Calculates EMA (5 day)' do - output = indicator.calculate(input_data, period: 5, price_key: :close) + output = indicator.calculate(input_data, period: 5, price_key: :close, date_time_key: :timestep) normalized_output = output.map(&:to_hash) expected_output = [ @@ -92,11 +92,11 @@ it 'Returns the valid options' do valid_options = indicator.valid_options - expect(valid_options).to eq(%i(period price_key)) + expect(valid_options).to eq(%i(period price_key date_time_key)) end it 'Validates options' do - valid_options = { period: 22, price_key: :close } + valid_options = { period: 22, price_key: :close, date_time_key: :timestep } options_validated = indicator.validate_options(valid_options) expect(options_validated).to eq(true) end From 149d838a98c83d6ff146833f38e83308bc3cb5dc Mon Sep 17 00:00:00 2001 From: Nick Pellant Date: Sat, 29 Feb 2020 14:36:00 +0000 Subject: [PATCH 69/84] Add date_time_key support to SMA indicator --- lib/technical_analysis/indicators/sma.rb | 12 +++++++----- spec/technical_analysis/indicators/indicator_spec.rb | 2 +- spec/technical_analysis/indicators/sma_spec.rb | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/technical_analysis/indicators/sma.rb b/lib/technical_analysis/indicators/sma.rb index d1027de..b01ea3c 100644 --- a/lib/technical_analysis/indicators/sma.rb +++ b/lib/technical_analysis/indicators/sma.rb @@ -20,7 +20,7 @@ def self.indicator_name # # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options - %i(period price_key) + %i(period price_key date_time_key) end # Validates the provided options for this technical indicator @@ -48,16 +48,18 @@ def self.min_data_size(period: 30, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the SMA # @param price_key [Symbol] The hash key for the price data. Default :value + # @param date_time_key [Symbol] The hash key for the date time data. Default :date_time # # @return [Array] An array of SmaValue instances - def self.calculate(data, period: 30, price_key: :value) + def self.calculate(data, period: 30, price_key: :value, date_time_key: :date_time) period = period.to_i price_key = price_key.to_sym + date_time_key = date_time_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) + Validation.validate_date_time_key(data, date_time_key) - data = data.sort_by { |row| row[:date_time] } + data = data.sort_by { |row| row[date_time_key] } output = [] period_values = [] @@ -65,7 +67,7 @@ def self.calculate(data, period: 30, price_key: :value) data.each do |v| period_values << v[price_key] if period_values.size == period - output << SmaValue.new(date_time: v[:date_time], sma: ArrayHelper.average(period_values)) + output << SmaValue.new(date_time: v[date_time_key], sma: ArrayHelper.average(period_values)) period_values.shift end end diff --git a/spec/technical_analysis/indicators/indicator_spec.rb b/spec/technical_analysis/indicators/indicator_spec.rb index 9fb8ef9..f8ed04d 100644 --- a/spec/technical_analysis/indicators/indicator_spec.rb +++ b/spec/technical_analysis/indicators/indicator_spec.rb @@ -38,7 +38,7 @@ it 'Calculates valid_options' do valid_options = indicator.calculate('sma', [], :valid_options, { period: 20, price_key: :close }) - expect(valid_options).to eq(%i(period price_key)) + expect(valid_options).to eq(%i(period price_key date_time_key)) end it 'Calculates validate_options' do diff --git a/spec/technical_analysis/indicators/sma_spec.rb b/spec/technical_analysis/indicators/sma_spec.rb index dc6cbe6..5cf6c08 100644 --- a/spec/technical_analysis/indicators/sma_spec.rb +++ b/spec/technical_analysis/indicators/sma_spec.rb @@ -3,12 +3,12 @@ describe 'Indicators' do describe "SMA" do - input_data = SpecHelper.get_test_data(:close) + input_data = SpecHelper.get_test_data(:close, date_time_key: :timestep) indicator = TechnicalAnalysis::Sma describe 'Simple Moving Average' do it 'Calculates SMA (5 day)' do - output = indicator.calculate(input_data, period: 5, price_key: :close) + output = indicator.calculate(input_data, period: 5, price_key: :close, date_time_key: :timestep) normalized_output = output.map(&:to_hash) expected_output = [ @@ -92,11 +92,11 @@ it 'Returns the valid options' do valid_options = indicator.valid_options - expect(valid_options).to eq(%i(period price_key)) + expect(valid_options).to eq(%i(period price_key date_time_key)) end it 'Validates options' do - valid_options = { period: 22, price_key: :close } + valid_options = { period: 22, price_key: :close, date_time_key: :timestep } options_validated = indicator.validate_options(valid_options) expect(options_validated).to eq(true) end From ee81300eef3ca8063b58b6f0216a894c81616b23 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 29 Feb 2020 15:55:49 +0000 Subject: [PATCH 70/84] Update rake requirement from ~> 10.0 to ~> 12.3 Updates the requirements on [rake](https://github.com/ruby/rake) to permit the latest version. - [Release notes](https://github.com/ruby/rake/releases) - [Changelog](https://github.com/ruby/rake/blob/master/History.rdoc) - [Commits](https://github.com/ruby/rake/compare/v10.5.0...v12.3.3) Signed-off-by: dependabot[bot] --- Gemfile.lock | 4 ++-- technical-analysis.gemspec | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f7cbf7c..1663b21 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,7 +7,7 @@ GEM remote: https://rubygems.org/ specs: diff-lcs (1.3) - rake (10.5.0) + rake (12.3.3) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) @@ -28,7 +28,7 @@ PLATFORMS DEPENDENCIES bundler (~> 1.16) - rake (~> 10.0) + rake (~> 12.3) rspec (~> 3.0) technical-analysis! yard (~> 0.9.20) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index 565f3a9..f479b61 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |spec| spec.metadata['allowed_push_host'] = 'https://rubygems.org' spec.add_development_dependency "bundler", "~> 1.16" - spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "rake", "~> 12.3" spec.add_development_dependency "rspec", "~> 3.0" spec.add_development_dependency "yard", "~> 0.9.20" end From af798a4d44dd3542f44083f65393f9f06c8f7415 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Mon, 2 Mar 2020 16:00:22 -0700 Subject: [PATCH 71/84] bundle --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1663b21..1b44fe2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,4 +34,4 @@ DEPENDENCIES yard (~> 0.9.20) BUNDLED WITH - 1.17.2 + 2.1.4 From 40a817643cee85bd6b19a1c073df20698c3c9cb3 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Mon, 2 Mar 2020 16:01:12 -0700 Subject: [PATCH 72/84] 0.2.2 --- technical-analysis.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index f479b61..c1e1af1 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "0.2.1" + spec.version = "0.2.2" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] spec.description = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} From 4f3b04d443b0504850e865f50c535eea2f29d336 Mon Sep 17 00:00:00 2001 From: thoran Date: Mon, 15 Jun 2020 09:57:35 +1000 Subject: [PATCH 73/84] + Weighted Moving Average --- lib/technical_analysis.rb | 1 + .../helpers/stock_calculation.rb | 8 ++ lib/technical_analysis/indicators/wma.rb | 97 +++++++++++++++ .../technical_analysis/indicators/wma_spec.rb | 115 ++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 lib/technical_analysis/indicators/wma.rb create mode 100644 spec/technical_analysis/indicators/wma_spec.rb diff --git a/lib/technical_analysis.rb b/lib/technical_analysis.rb index f4368e8..e6b0e41 100644 --- a/lib/technical_analysis.rb +++ b/lib/technical_analysis.rb @@ -40,4 +40,5 @@ require 'technical_analysis/indicators/vi' require 'technical_analysis/indicators/vpt' require 'technical_analysis/indicators/vwap' +require 'technical_analysis/indicators/wma' require 'technical_analysis/indicators/wr' diff --git a/lib/technical_analysis/helpers/stock_calculation.rb b/lib/technical_analysis/helpers/stock_calculation.rb index 6da25da..1314fb5 100644 --- a/lib/technical_analysis/helpers/stock_calculation.rb +++ b/lib/technical_analysis/helpers/stock_calculation.rb @@ -21,5 +21,13 @@ def self.ema(current_value, data, period, prev_value) end end + def self.wma(data) + intermediate_values = [] + data.each_with_index do |datum, i| + intermediate_values << datum * (i + 1)/(data.size * (data.size + 1)/2).to_f + end + intermediate_values.sum + end + end end diff --git a/lib/technical_analysis/indicators/wma.rb b/lib/technical_analysis/indicators/wma.rb new file mode 100644 index 0000000..6e51de8 --- /dev/null +++ b/lib/technical_analysis/indicators/wma.rb @@ -0,0 +1,97 @@ +module TechnicalAnalysis + # Weighted Moving Average + class Wma < Indicator + + # Returns the symbol of the technical indicator + # + # @return [String] A string of the symbol of the technical indicator + def self.indicator_symbol + "wma" + end + + # Returns the name of the technical indicator + # + # @return [String] A string of the name of the technical indicator + def self.indicator_name + "Weighted Moving Average" + end + + # Returns an array of valid keys for options for this technical indicator + # + # @return [Array] An array of keys as symbols for valid options for this technical indicator + def self.valid_options + %i(period price_key date_time_key) + end + + # Validates the provided options for this technical indicator + # + # @param options [Hash] The options for the technical indicator to be validated + # + # @return [Boolean] Returns true if options are valid or raises a ValidationError if they're not + def self.validate_options(options) + Validation.validate_options(options, valid_options) + end + + # Calculates the minimum number of observations needed to calculate the technical indicator + # + # @param options [Hash] The options for the technical indicator + # + # @return [Integer] Returns the minimum number of observations needed to calculate the technical + # indicator based on the options provided + def self.min_data_size(period: 30, **params) + period.to_i + end + + # Calculates the weighted moving average (WMA) for the data over the given period + # https://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average + # + # @param data [Array] Array of hashes with keys (:date_time, :value) + # @param period [Integer] The given period to calculate the WMA + # @param price_key [Symbol] The hash key for the price data. Default :value + # @param date_time_key [Symbol] The hash key for the date time data. Default :date_time + # + # @return [Array] An array of WmaValue instances + def self.calculate(data, period: 30, price_key: :value, date_time_key: :date_time) + period = period.to_i + price_key = price_key.to_sym + date_time_key = date_time_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 = [] + period_values = [] + previous_wma = nil + data.each do |v| + period_values << v[price_key] + if period_values.size == period + wma = StockCalculation.wma(period_values) + output << WmaValue.new(date_time: v[date_time_key], wma: wma) + period_values.shift + end + end + output.sort_by(&:date_time).reverse + end + + end + + # The value class to be returned by calculations + class WmaValue + + # @return [String] the date_time of the obversation as it was provided + attr_accessor :date_time + + # @return [Float] the wma calculation value + attr_accessor :wma + + def initialize(date_time: nil, wma: nil) + @date_time = date_time + @wma = wma + end + + # @return [Hash] the attributes as a hash + def to_hash + { date_time: @date_time, wma: @wma } + end + end +end diff --git a/spec/technical_analysis/indicators/wma_spec.rb b/spec/technical_analysis/indicators/wma_spec.rb new file mode 100644 index 0000000..8c3bf2c --- /dev/null +++ b/spec/technical_analysis/indicators/wma_spec.rb @@ -0,0 +1,115 @@ +require 'technical-analysis' +require 'spec_helper' + +describe 'Indicators' do + describe "WMA" do + input_data = SpecHelper.get_test_data(:close, date_time_key: :timestep) + indicator = TechnicalAnalysis::Wma + + describe 'Weighted Moving Average' do + it 'Calculates WMA (5 day)' do + output = indicator.calculate(input_data, period: 5, price_key: :close, date_time_key: :timestep) + normalized_output = output.map(&:to_hash) + + expected_output = [ + {:date_time=>"2019-01-09T00:00:00.000Z", :wma=>150.13666666666666}, + {:date_time=>"2019-01-08T00:00:00.000Z", :wma=>148.83666666666667}, + {:date_time=>"2019-01-07T00:00:00.000Z", :wma=>148.856}, + {:date_time=>"2019-01-04T00:00:00.000Z", :wma=>150.36866666666666}, + {:date_time=>"2019-01-03T00:00:00.000Z", :wma=>152.29733333333334}, + {:date_time=>"2019-01-02T00:00:00.000Z", :wma=>157.248}, + {:date_time=>"2018-12-31T00:00:00.000Z", :wma=>156.216}, + {:date_time=>"2018-12-28T00:00:00.000Z", :wma=>154.77666666666667}, + {:date_time=>"2018-12-27T00:00:00.000Z", :wma=>153.88066666666666}, + {:date_time=>"2018-12-26T00:00:00.000Z", :wma=>153.32733333333334}, + {:date_time=>"2018-12-24T00:00:00.000Z", :wma=>153.02733333333333}, + {:date_time=>"2018-12-21T00:00:00.000Z", :wma=>157.31466666666665}, + {:date_time=>"2018-12-20T00:00:00.000Z", :wma=>161.28533333333334}, + {:date_time=>"2018-12-19T00:00:00.000Z", :wma=>164.164}, + {:date_time=>"2018-12-18T00:00:00.000Z", :wma=>166.23666666666665}, + {:date_time=>"2018-12-17T00:00:00.000Z", :wma=>166.75333333333333}, + {:date_time=>"2018-12-14T00:00:00.000Z", :wma=>168.35733333333332}, + {:date_time=>"2018-12-13T00:00:00.000Z", :wma=>169.64866666666666}, + {:date_time=>"2018-12-12T00:00:00.000Z", :wma=>169.368}, + {:date_time=>"2018-12-11T00:00:00.000Z", :wma=>170.21}, + {:date_time=>"2018-12-10T00:00:00.000Z", :wma=>172.28799999999998}, + {:date_time=>"2018-12-07T00:00:00.000Z", :wma=>174.64133333333334}, + {:date_time=>"2018-12-06T00:00:00.000Z", :wma=>178.102}, + {:date_time=>"2018-12-04T00:00:00.000Z", :wma=>179.90066666666667}, + {:date_time=>"2018-12-03T00:00:00.000Z", :wma=>180.87933333333334}, + {:date_time=>"2018-11-30T00:00:00.000Z", :wma=>178.46800000000002}, + {:date_time=>"2018-11-29T00:00:00.000Z", :wma=>177.71733333333333}, + {:date_time=>"2018-11-28T00:00:00.000Z", :wma=>176.4586666666667}, + {:date_time=>"2018-11-27T00:00:00.000Z", :wma=>174.47266666666667}, + {:date_time=>"2018-11-26T00:00:00.000Z", :wma=>175.49466666666666}, + {:date_time=>"2018-11-23T00:00:00.000Z", :wma=>177.65066666666667}, + {:date_time=>"2018-11-21T00:00:00.000Z", :wma=>181.858}, + {:date_time=>"2018-11-20T00:00:00.000Z", :wma=>185.23666666666668}, + {:date_time=>"2018-11-19T00:00:00.000Z", :wma=>189.56533333333334}, + {:date_time=>"2018-11-16T00:00:00.000Z", :wma=>191.488}, + {:date_time=>"2018-11-15T00:00:00.000Z", :wma=>191.58333333333334}, + {:date_time=>"2018-11-14T00:00:00.000Z", :wma=>193.524}, + {:date_time=>"2018-11-13T00:00:00.000Z", :wma=>198.54466666666667}, + {:date_time=>"2018-11-12T00:00:00.000Z", :wma=>202.52466666666666}, + {:date_time=>"2018-11-09T00:00:00.000Z", :wma=>206.35266666666666}, + {:date_time=>"2018-11-08T00:00:00.000Z", :wma=>206.948}, + {:date_time=>"2018-11-07T00:00:00.000Z", :wma=>207.11866666666666}, + {:date_time=>"2018-11-06T00:00:00.000Z", :wma=>207.39666666666665}, + {:date_time=>"2018-11-05T00:00:00.000Z", :wma=>210.37}, + {:date_time=>"2018-11-02T00:00:00.000Z", :wma=>214.78}, + {:date_time=>"2018-11-01T00:00:00.000Z", :wma=>217.81466666666665}, + {:date_time=>"2018-10-31T00:00:00.000Z", :wma=>215.7746666666667}, + {:date_time=>"2018-10-30T00:00:00.000Z", :wma=>214.60333333333335}, + {:date_time=>"2018-10-29T00:00:00.000Z", :wma=>215.91400000000002}, + {:date_time=>"2018-10-26T00:00:00.000Z", :wma=>218.13866666666667}, + {:date_time=>"2018-10-25T00:00:00.000Z", :wma=>219.21066666666667}, + {:date_time=>"2018-10-24T00:00:00.000Z", :wma=>218.864}, + {:date_time=>"2018-10-23T00:00:00.000Z", :wma=>220.494}, + {:date_time=>"2018-10-22T00:00:00.000Z", :wma=>219.53866666666667}, + {:date_time=>"2018-10-19T00:00:00.000Z", :wma=>219.05733333333333}, + {:date_time=>"2018-10-18T00:00:00.000Z", :wma=>219.20933333333335}, + {:date_time=>"2018-10-17T00:00:00.000Z", :wma=>220.35333333333335}, + {:date_time=>"2018-10-16T00:00:00.000Z", :wma=>219.452}, + {:date_time=>"2018-10-15T00:00:00.000Z", :wma=>218.54533333333336} + ] + + expect(normalized_output).to eq(expected_output) + end + + it "Throws exception if not enough data" do + expect {indicator.calculate(input_data, period: input_data.size+1, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Returns the symbol' do + indicator_symbol = indicator.indicator_symbol + expect(indicator_symbol).to eq('wma') + end + + it 'Returns the name' do + indicator_name = indicator.indicator_name + expect(indicator_name).to eq('Weighted Moving Average') + end + + it 'Returns the valid options' do + valid_options = indicator.valid_options + expect(valid_options).to eq(%i(period price_key date_time_key)) + end + + it 'Validates options' do + valid_options = { period: 22, price_key: :close, date_time_key: :timestep } + options_validated = indicator.validate_options(valid_options) + expect(options_validated).to eq(true) + end + + it 'Throws exception for invalid options' do + invalid_options = { test: 10 } + expect { indicator.validate_options(invalid_options) }.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + end + + it 'Calculates minimum data size' do + options = { period: 4 } + expect(indicator.min_data_size(**options)).to eq(4) + end + end + end +end From 4088e63fbdb4384e3049ce3dd05e89951185a7f7 Mon Sep 17 00:00:00 2001 From: thoran Date: Mon, 29 Jun 2020 22:46:42 +1000 Subject: [PATCH 74/84] + empty lines as per review --- lib/technical_analysis/indicators/wma.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/technical_analysis/indicators/wma.rb b/lib/technical_analysis/indicators/wma.rb index 6e51de8..fa6a5c9 100644 --- a/lib/technical_analysis/indicators/wma.rb +++ b/lib/technical_analysis/indicators/wma.rb @@ -58,10 +58,13 @@ def self.calculate(data, period: 30, price_key: :value, date_time_key: :date_tim 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 = [] period_values = [] previous_wma = nil + data.each do |v| period_values << v[price_key] if period_values.size == period From 5236e9ff96699f3e5f7cd27851fb149d8147201f Mon Sep 17 00:00:00 2001 From: thoran Date: Fri, 31 Jul 2020 14:37:40 +1000 Subject: [PATCH 75/84] fix: ~ indicators/adx.rb, so that it works for other than the default 14 period values. --- lib/technical_analysis/indicators/adx.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/adx.rb b/lib/technical_analysis/indicators/adx.rb index 1bcda37..abe8506 100644 --- a/lib/technical_analysis/indicators/adx.rb +++ b/lib/technical_analysis/indicators/adx.rb @@ -85,7 +85,7 @@ def self.calculate(data, period: 14) if prev_adx.nil? adx = ArrayHelper.average(dx_values) else - adx = ((prev_adx * 13) + dx) / period.to_f + adx = ((prev_adx * (period - 1)) + dx) / period.to_f end output << AdxValue.new(date_time: v[:date_time], adx: adx, di_pos: di_pos, di_neg: di_neg) From 2ba75f622c88f98966706fe0f415c2fe83a6d098 Mon Sep 17 00:00:00 2001 From: Matt Von Lintel Date: Mon, 3 Aug 2020 14:31:49 -0600 Subject: [PATCH 76/84] 0.2.3 --- technical-analysis.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technical-analysis.gemspec b/technical-analysis.gemspec index c1e1af1..099220f 100644 --- a/technical-analysis.gemspec +++ b/technical-analysis.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = "technical-analysis" - spec.version = "0.2.2" + spec.version = "0.2.3" spec.authors = ["Intrinio"] spec.email = ["admin@intrinio.com"] spec.description = %q{A Ruby library for performing technical analysis on stock prices and other data sets.} From abf8f2685a3f978cbab463ee3f17efd443e41ef8 Mon Sep 17 00:00:00 2001 From: Jon Marshall Smith Date: Mon, 10 Aug 2020 18:12:35 -0400 Subject: [PATCH 77/84] Add date_time_key support to RSI indicator --- lib/technical_analysis/indicators/rsi.rb | 11 ++++++----- spec/technical_analysis/indicators/rsi_spec.rb | 10 +++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/lib/technical_analysis/indicators/rsi.rb b/lib/technical_analysis/indicators/rsi.rb index 0ee094f..ca5cbd5 100644 --- a/lib/technical_analysis/indicators/rsi.rb +++ b/lib/technical_analysis/indicators/rsi.rb @@ -20,7 +20,7 @@ def self.indicator_name # # @return [Array] An array of keys as symbols for valid options for this technical indicator def self.valid_options - %i(period price_key) + %i(period price_key date_time_key) end # Validates the provided options for this technical indicator @@ -48,16 +48,17 @@ def self.min_data_size(period: 14, **params) # @param data [Array] Array of hashes with keys (:date_time, :value) # @param period [Integer] The given period to calculate the RSI # @param price_key [Symbol] The hash key for the price data. Default :value + # @param date_time_key [Symbol] The hash key for the date time data. Default :date_time # # @return [Array] An array of RsiValue instances - def self.calculate(data, period: 14, price_key: :value) + 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) + Validation.validate_date_time_key(data, date_time_key) - data = data.sort_by { |row| row[:date_time] } + data = data.sort_by { |row| row[date_time_key] } output = [] prev_price = data.shift[price_key] @@ -96,7 +97,7 @@ def self.calculate(data, period: 14, price_key: :value) rsi = (100.00 - (100.00 / (1.00 + rs))) end - output << RsiValue.new(date_time: v[:date_time], rsi: rsi) + output << RsiValue.new(date_time: v[date_time_key], rsi: rsi) prev_avg = { gain: avg_gain, loss: avg_loss } price_changes.shift diff --git a/spec/technical_analysis/indicators/rsi_spec.rb b/spec/technical_analysis/indicators/rsi_spec.rb index 9c94836..569f8c5 100644 --- a/spec/technical_analysis/indicators/rsi_spec.rb +++ b/spec/technical_analysis/indicators/rsi_spec.rb @@ -3,12 +3,12 @@ describe 'Indicators' do describe "RSI" do - input_data = SpecHelper.get_test_data(:close) + input_data = SpecHelper.get_test_data(:close, date_time_key: :timestep) indicator = TechnicalAnalysis::Rsi describe 'Relative Strength Index' do it 'Calculates RSI (14 day)' do - output = indicator.calculate(input_data, period: 14, price_key: :close) + output = indicator.calculate(input_data, period: 14, price_key: :close, date_time_key: :timestep) normalized_output = output.map(&:to_hash) expected_output = [ @@ -67,7 +67,7 @@ end it "Throws exception if not enough data" do - expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) + expect {indicator.calculate(input_data, period: input_data.size+2, price_key: :close, date_time_key: :time)}.to raise_exception(TechnicalAnalysis::Validation::ValidationError) end it 'Returns the symbol' do @@ -82,11 +82,11 @@ it 'Returns the valid options' do valid_options = indicator.valid_options - expect(valid_options).to eq(%i(period price_key)) + expect(valid_options).to eq(%i(period price_key date_time_key)) end it 'Validates options' do - valid_options = { period: 22, price_key: :close } + valid_options = { period: 22, price_key: :close, date_time_key: :timespec } options_validated = indicator.validate_options(valid_options) expect(options_validated).to eq(true) end From 2c1f3e514e2e3e6ad3f26b744baa9155e7db0336 Mon Sep 17 00:00:00 2001 From: civilframe Date: Tue, 11 Aug 2020 10:53:19 -0600 Subject: [PATCH 78/84] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d7b2c37..61e57b7 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,7 @@ The following technical indicators are supported: - Vortex Indicator (VI) - Volume-price Trend (VPT) - Volume Weighted Average Price (VWAP) +- Weighted Moving Average (WMA) - Williams %R (WR) ## Install From 754fcd20788b7ac93e8ab8a8e9adc3c2c254aa90 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Tue, 11 Aug 2020 10:56:23 -0600 Subject: [PATCH 79/84] bundle --- Gemfile.lock | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 1b44fe2..9beadef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,27 +1,27 @@ PATH remote: . specs: - technical-analysis (0.2.1) + technical-analysis (0.2.3) GEM remote: https://rubygems.org/ specs: - diff-lcs (1.3) + diff-lcs (1.4.4) rake (12.3.3) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) rspec-mocks (~> 3.9.0) - rspec-core (3.9.1) - rspec-support (~> 3.9.1) - rspec-expectations (3.9.0) + rspec-core (3.9.2) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) - rspec-support (3.9.2) - yard (0.9.24) + rspec-support (3.9.3) + yard (0.9.25) PLATFORMS ruby @@ -34,4 +34,4 @@ DEPENDENCIES yard (~> 0.9.20) BUNDLED WITH - 2.1.4 + 1.17.1 From a19eb249d7d59a5490a0bddee6375fa3eeb77b01 Mon Sep 17 00:00:00 2001 From: Alex Solo Date: Tue, 11 Aug 2020 15:10:31 -0600 Subject: [PATCH 80/84] fixed test --- .../helpers/stock_calculation.rb | 2 +- .../technical_analysis/indicators/wma_spec.rb | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/technical_analysis/helpers/stock_calculation.rb b/lib/technical_analysis/helpers/stock_calculation.rb index 1314fb5..6f1d8d2 100644 --- a/lib/technical_analysis/helpers/stock_calculation.rb +++ b/lib/technical_analysis/helpers/stock_calculation.rb @@ -26,7 +26,7 @@ def self.wma(data) data.each_with_index do |datum, i| intermediate_values << datum * (i + 1)/(data.size * (data.size + 1)/2).to_f end - intermediate_values.sum + ArrayHelper.sum(intermediate_values) end end diff --git a/spec/technical_analysis/indicators/wma_spec.rb b/spec/technical_analysis/indicators/wma_spec.rb index 8c3bf2c..20d4a87 100644 --- a/spec/technical_analysis/indicators/wma_spec.rb +++ b/spec/technical_analysis/indicators/wma_spec.rb @@ -20,26 +20,26 @@ {:date_time=>"2019-01-02T00:00:00.000Z", :wma=>157.248}, {:date_time=>"2018-12-31T00:00:00.000Z", :wma=>156.216}, {:date_time=>"2018-12-28T00:00:00.000Z", :wma=>154.77666666666667}, - {:date_time=>"2018-12-27T00:00:00.000Z", :wma=>153.88066666666666}, - {:date_time=>"2018-12-26T00:00:00.000Z", :wma=>153.32733333333334}, + {:date_time=>"2018-12-27T00:00:00.000Z", :wma=>153.88066666666668}, + {:date_time=>"2018-12-26T00:00:00.000Z", :wma=>153.3273333333333}, {:date_time=>"2018-12-24T00:00:00.000Z", :wma=>153.02733333333333}, - {:date_time=>"2018-12-21T00:00:00.000Z", :wma=>157.31466666666665}, + {:date_time=>"2018-12-21T00:00:00.000Z", :wma=>157.31466666666668}, {:date_time=>"2018-12-20T00:00:00.000Z", :wma=>161.28533333333334}, {:date_time=>"2018-12-19T00:00:00.000Z", :wma=>164.164}, {:date_time=>"2018-12-18T00:00:00.000Z", :wma=>166.23666666666665}, {:date_time=>"2018-12-17T00:00:00.000Z", :wma=>166.75333333333333}, - {:date_time=>"2018-12-14T00:00:00.000Z", :wma=>168.35733333333332}, + {:date_time=>"2018-12-14T00:00:00.000Z", :wma=>168.35733333333334}, {:date_time=>"2018-12-13T00:00:00.000Z", :wma=>169.64866666666666}, {:date_time=>"2018-12-12T00:00:00.000Z", :wma=>169.368}, {:date_time=>"2018-12-11T00:00:00.000Z", :wma=>170.21}, - {:date_time=>"2018-12-10T00:00:00.000Z", :wma=>172.28799999999998}, + {:date_time=>"2018-12-10T00:00:00.000Z", :wma=>172.288}, {:date_time=>"2018-12-07T00:00:00.000Z", :wma=>174.64133333333334}, {:date_time=>"2018-12-06T00:00:00.000Z", :wma=>178.102}, - {:date_time=>"2018-12-04T00:00:00.000Z", :wma=>179.90066666666667}, + {:date_time=>"2018-12-04T00:00:00.000Z", :wma=>179.9006666666667}, {:date_time=>"2018-12-03T00:00:00.000Z", :wma=>180.87933333333334}, - {:date_time=>"2018-11-30T00:00:00.000Z", :wma=>178.46800000000002}, + {:date_time=>"2018-11-30T00:00:00.000Z", :wma=>178.468}, {:date_time=>"2018-11-29T00:00:00.000Z", :wma=>177.71733333333333}, - {:date_time=>"2018-11-28T00:00:00.000Z", :wma=>176.4586666666667}, + {:date_time=>"2018-11-28T00:00:00.000Z", :wma=>176.45866666666666}, {:date_time=>"2018-11-27T00:00:00.000Z", :wma=>174.47266666666667}, {:date_time=>"2018-11-26T00:00:00.000Z", :wma=>175.49466666666666}, {:date_time=>"2018-11-23T00:00:00.000Z", :wma=>177.65066666666667}, @@ -47,30 +47,30 @@ {:date_time=>"2018-11-20T00:00:00.000Z", :wma=>185.23666666666668}, {:date_time=>"2018-11-19T00:00:00.000Z", :wma=>189.56533333333334}, {:date_time=>"2018-11-16T00:00:00.000Z", :wma=>191.488}, - {:date_time=>"2018-11-15T00:00:00.000Z", :wma=>191.58333333333334}, + {:date_time=>"2018-11-15T00:00:00.000Z", :wma=>191.58333333333331}, {:date_time=>"2018-11-14T00:00:00.000Z", :wma=>193.524}, {:date_time=>"2018-11-13T00:00:00.000Z", :wma=>198.54466666666667}, {:date_time=>"2018-11-12T00:00:00.000Z", :wma=>202.52466666666666}, {:date_time=>"2018-11-09T00:00:00.000Z", :wma=>206.35266666666666}, {:date_time=>"2018-11-08T00:00:00.000Z", :wma=>206.948}, - {:date_time=>"2018-11-07T00:00:00.000Z", :wma=>207.11866666666666}, + {:date_time=>"2018-11-07T00:00:00.000Z", :wma=>207.11866666666668}, {:date_time=>"2018-11-06T00:00:00.000Z", :wma=>207.39666666666665}, {:date_time=>"2018-11-05T00:00:00.000Z", :wma=>210.37}, {:date_time=>"2018-11-02T00:00:00.000Z", :wma=>214.78}, {:date_time=>"2018-11-01T00:00:00.000Z", :wma=>217.81466666666665}, {:date_time=>"2018-10-31T00:00:00.000Z", :wma=>215.7746666666667}, - {:date_time=>"2018-10-30T00:00:00.000Z", :wma=>214.60333333333335}, + {:date_time=>"2018-10-30T00:00:00.000Z", :wma=>214.60333333333332}, {:date_time=>"2018-10-29T00:00:00.000Z", :wma=>215.91400000000002}, {:date_time=>"2018-10-26T00:00:00.000Z", :wma=>218.13866666666667}, {:date_time=>"2018-10-25T00:00:00.000Z", :wma=>219.21066666666667}, - {:date_time=>"2018-10-24T00:00:00.000Z", :wma=>218.864}, - {:date_time=>"2018-10-23T00:00:00.000Z", :wma=>220.494}, - {:date_time=>"2018-10-22T00:00:00.000Z", :wma=>219.53866666666667}, + {:date_time=>"2018-10-24T00:00:00.000Z", :wma=>218.86400000000003}, + {:date_time=>"2018-10-23T00:00:00.000Z", :wma=>220.49400000000003}, + {:date_time=>"2018-10-22T00:00:00.000Z", :wma=>219.53866666666664}, {:date_time=>"2018-10-19T00:00:00.000Z", :wma=>219.05733333333333}, {:date_time=>"2018-10-18T00:00:00.000Z", :wma=>219.20933333333335}, {:date_time=>"2018-10-17T00:00:00.000Z", :wma=>220.35333333333335}, {:date_time=>"2018-10-16T00:00:00.000Z", :wma=>219.452}, - {:date_time=>"2018-10-15T00:00:00.000Z", :wma=>218.54533333333336} + {:date_time=>"2018-10-15T00:00:00.000Z", :wma=>218.54533333333333} ] expect(normalized_output).to eq(expected_output) From abc776cb5400928bce8b5af1dc6caa1a4d9601c1 Mon Sep 17 00:00:00 2001 From: Shawn Snyder Date: Thu, 19 May 2022 16:45:11 -0500 Subject: [PATCH 81/84] Change loop to lookup --- .../indicators/indicator.rb | 47 +++++++++++++++++-- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/lib/technical_analysis/indicators/indicator.rb b/lib/technical_analysis/indicators/indicator.rb index 585c9b0..f518b80 100644 --- a/lib/technical_analysis/indicators/indicator.rb +++ b/lib/technical_analysis/indicators/indicator.rb @@ -54,17 +54,56 @@ def self.roster ] end + def self.roster_hash + { + TechnicalAnalysis::Adi.indicator_symbol => TechnicalAnalysis::Adi, + TechnicalAnalysis::Adtv.indicator_symbol => TechnicalAnalysis::Adtv, + TechnicalAnalysis::Adx.indicator_symbol => TechnicalAnalysis::Adx, + TechnicalAnalysis::Ao.indicator_symbol => TechnicalAnalysis::Ao, + TechnicalAnalysis::Atr.indicator_symbol => TechnicalAnalysis::Atr, + TechnicalAnalysis::Bb.indicator_symbol => TechnicalAnalysis::Bb, + TechnicalAnalysis::Cci.indicator_symbol => TechnicalAnalysis::Cci, + TechnicalAnalysis::Cmf.indicator_symbol => TechnicalAnalysis::Cmf, + TechnicalAnalysis::Cr.indicator_symbol => TechnicalAnalysis::Cr, + TechnicalAnalysis::Dc.indicator_symbol => TechnicalAnalysis::Dc, + TechnicalAnalysis::Dlr.indicator_symbol => TechnicalAnalysis::Dlr, + TechnicalAnalysis::Dpo.indicator_symbol => TechnicalAnalysis::Dpo, + TechnicalAnalysis::Dr.indicator_symbol => TechnicalAnalysis::Dr, + TechnicalAnalysis::Eom.indicator_symbol => TechnicalAnalysis::Eom, + TechnicalAnalysis::Fi.indicator_symbol => TechnicalAnalysis::Fi, + TechnicalAnalysis::Ichimoku.indicator_symbol => TechnicalAnalysis::Ichimoku, + TechnicalAnalysis::Kc.indicator_symbol => TechnicalAnalysis::Kc, + TechnicalAnalysis::Kst.indicator_symbol => TechnicalAnalysis::Kst, + TechnicalAnalysis::Macd.indicator_symbol => TechnicalAnalysis::Macd, + TechnicalAnalysis::Mfi.indicator_symbol => TechnicalAnalysis::Mfi, + TechnicalAnalysis::Mi.indicator_symbol => TechnicalAnalysis::Mi, + TechnicalAnalysis::Nvi.indicator_symbol => TechnicalAnalysis::Nvi, + TechnicalAnalysis::Obv.indicator_symbol => TechnicalAnalysis::Obv, + TechnicalAnalysis::ObvMean.indicator_symbol => TechnicalAnalysis::ObvMean, + TechnicalAnalysis::Rsi.indicator_symbol => TechnicalAnalysis::Rsi, + TechnicalAnalysis::Sma.indicator_symbol => TechnicalAnalysis::Sma, + TechnicalAnalysis::Sr.indicator_symbol => TechnicalAnalysis::Sr, + TechnicalAnalysis::Trix.indicator_symbol => TechnicalAnalysis::Trix, + TechnicalAnalysis::Tsi.indicator_symbol => TechnicalAnalysis::Tsi, + TechnicalAnalysis::Uo.indicator_symbol => TechnicalAnalysis::Uo, + TechnicalAnalysis::Vi.indicator_symbol => TechnicalAnalysis::Vi, + TechnicalAnalysis::Vpt.indicator_symbol => TechnicalAnalysis::Vpt, + TechnicalAnalysis::Vwap.indicator_symbol => TechnicalAnalysis::Vwap, + TechnicalAnalysis::Wr.indicator_symbol => TechnicalAnalysis::Wr, + } + end + # Finds the applicable indicator and returns an instance # # @param indicator_symbol [String] Downcased string of the indicator symbol # # @return TechnicalAnalysis::ClassName def self.find(indicator_symbol) - roster.each do |indicator| - return indicator if indicator.indicator_symbol == indicator_symbol + if roster_hash.key?(indicator_symbol) + roster_hash[indicator_symbol] + else + nil end - - nil end # Find the applicable indicator and looks up the value From 082ce7bd055e24b5e757f35ad398cfd1b1a59e66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Mar 2024 16:52:44 +0000 Subject: [PATCH 82/84] Bump yard from 0.9.25 to 0.9.36 Bumps [yard](https://github.com/lsegal/yard) from 0.9.25 to 0.9.36. - [Release notes](https://github.com/lsegal/yard/releases) - [Changelog](https://github.com/lsegal/yard/blob/main/CHANGELOG.md) - [Commits](https://github.com/lsegal/yard/compare/v0.9.25...v0.9.36) --- updated-dependencies: - dependency-name: yard dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9beadef..463e822 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -21,7 +21,7 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-support (3.9.3) - yard (0.9.25) + yard (0.9.36) PLATFORMS ruby From bdd7ef0949c3cd7618a2e6149a408bbcd0a00db3 Mon Sep 17 00:00:00 2001 From: Jason Landry Date: Tue, 16 Jul 2024 13:57:35 -0400 Subject: [PATCH 83/84] handle division by zero --- lib/technical_analysis/indicators/mfi.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/technical_analysis/indicators/mfi.rb b/lib/technical_analysis/indicators/mfi.rb index 375ffaf..942e043 100644 --- a/lib/technical_analysis/indicators/mfi.rb +++ b/lib/technical_analysis/indicators/mfi.rb @@ -80,7 +80,14 @@ def self.calculate(data, period: 14) positive_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.positive? ? rmf : 0 }) negative_period_flows = ArrayHelper.sum(raw_money_flows.map { |rmf| rmf.negative? ? rmf.abs : 0 }) - money_flow_ratio = (positive_period_flows / negative_period_flows) + if positive_period_flows == 0 + money_flow_ratio = 0 + elsif negative_period_flows == 0 + money_flow_ratio = positive_period_flows + else + money_flow_ratio = (positive_period_flows / negative_period_flows) + end + mfi = (100.00 - (100.00 / (1.0 + money_flow_ratio))) output << MfiValue.new(date_time: v[:date_time], mfi: mfi) From af8d58437c13a8ec196e5cd1558392a11e039b0e Mon Sep 17 00:00:00 2001 From: brett howell Date: Sat, 13 Sep 2025 11:38:07 -0700 Subject: [PATCH 84/84] Update README.md l added a new title and lm merging with codeland --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 61e57b7..6fd0a72 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# technical-analysis +# technical-analysisfor codeland A Ruby library for performing technical analysis on stock prices and other data sets. ## Indicators