Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
990d509
First wave of technical indicators (#34)
atsmith813 Jan 31, 2019
183df23
Create Indicator class
atsmith813 Feb 1, 2019
477e591
Add Indicator inheritance and symbol methods
atsmith813 Feb 1, 2019
787f91a
Change old librarian reference to indicator
atsmith813 Feb 1, 2019
194f4d2
Add min_data_size method to each indicator
atsmith813 Feb 1, 2019
b37c29a
Symbol to indicator_symbol and add indicator_name
atsmith813 Feb 1, 2019
37280f8
Add valid_options and validate_options
atsmith813 Feb 2, 2019
fd5a29e
Add methods to indicators
atsmith813 Feb 2, 2019
e2c2f40
Add default valid_options method to indicator
atsmith813 Feb 2, 2019
3df4155
Sort output by date_time desc, update specs
atsmith813 Feb 2, 2019
921b9c5
Update specs for each indicator
atsmith813 Feb 4, 2019
6ca431d
Create specs for Indicator
atsmith813 Feb 4, 2019
f58855e
Change params to integers inside calculations
atsmith813 Feb 4, 2019
6dfcaf0
Symbolize price_key in calculations
atsmith813 Feb 4, 2019
19010e9
Fix typo
atsmith813 Feb 4, 2019
4f93751
Minor typo updates
atsmith813 Feb 6, 2019
4b394dc
Add Yard comments/documentation
atsmith813 Feb 7, 2019
384ef15
Add Yard comments/documentation
atsmith813 Feb 7, 2019
b6a79c3
Add Yard comments/documentation & private methods
atsmith813 Feb 7, 2019
590027e
Update macd min_data_size
atsmith813 Feb 7, 2019
40d4fd8
Add Yard comments/documentation
atsmith813 Feb 7, 2019
942d68d
Add Yard comments/documentation
atsmith813 Feb 7, 2019
06e96e0
Update min_data_size for obv_mean and ichimoku
atsmith813 Feb 8, 2019
1b19e4b
Make helper methods private
atsmith813 Feb 8, 2019
b426240
Update yard comments
atsmith813 Feb 11, 2019
0c1a154
Update data size validator in calculate
atsmith813 Feb 11, 2019
f1ebb5c
Update yard comments
atsmith813 Feb 11, 2019
a2b6923
Move roster and calculations to private
atsmith813 Feb 13, 2019
6af104f
Update array helpers for sorting by date_time
atsmith813 Feb 13, 2019
636cf41
Update spec for returning IndicatorValue
atsmith813 Feb 13, 2019
e618600
Update Adx with AdxValue
atsmith813 Feb 13, 2019
984cca9
Add AoValue
atsmith813 Feb 13, 2019
0f8cda6
Fix atr
atsmith813 Feb 13, 2019
9af83bc
Add BbValue
atsmith813 Feb 13, 2019
dd77168
Add CciValue, CmfValue, CrValue, DcValue, DlrValue
atsmith813 Feb 13, 2019
92adaf0
Add IndicatorValue
atsmith813 Feb 13, 2019
2a42d09
Add IndicatorValue
atsmith813 Feb 14, 2019
261cc11
Logic updates
atsmith813 Mar 6, 2019
4c82f05
Add date_time_key validation to vpt
atsmith813 Mar 6, 2019
99ffed4
Change logic to sort data by date_time
atsmith813 Mar 6, 2019
2f892cf
Update references to sum ArrayHelper method
atsmith813 Mar 6, 2019
76e40b6
Update references to average and mean ArrayHelper
atsmith813 Mar 6, 2019
ed1e559
Update references to standard_deviation
atsmith813 Mar 6, 2019
9170c21
Create ArrayHelper spec
atsmith813 Mar 6, 2019
1bd8c28
Add validation test for numeric_data
atsmith813 Mar 6, 2019
5c30377
Update references to Validation in module
atsmith813 Mar 6, 2019
a135cc8
Remove forced use of timestamp format
atsmith813 Mar 6, 2019
30622ea
Removed duplicate
alexnsolo Mar 6, 2019
817450a
Made Indicator.roster public
alexnsolo Mar 6, 2019
bc310bf
Updated README
alexnsolo Mar 6, 2019
0fe6a11
v0.1.0
alexnsolo Mar 6, 2019
0004a72
gitignore
alexnsolo Mar 6, 2019
71f9426
Removed old spec
alexnsolo Mar 6, 2019
cfabd0b
CircleCI Config
alexnsolo Mar 6, 2019
2d1d07e
CircleCI Config
alexnsolo Mar 6, 2019
65d9eed
CircleCI Config
alexnsolo Mar 6, 2019
fe6c34f
Updated gemspec
alexnsolo Mar 6, 2019
29b9460
Update README with code samples and more details
atsmith813 Mar 18, 2019
c498da0
Add Volume Weighted Average Price (VWAP)
atsmith813 Mar 18, 2019
01a3ce0
README updates for Indicator class
atsmith813 Mar 18, 2019
4b9f17a
Add volume to Yard doc comment
atsmith813 Mar 18, 2019
80edbd6
More README updates, break usage into 2 sections
atsmith813 Mar 19, 2019
89220b7
Add VWAP to README
atsmith813 Mar 19, 2019
aa89438
Merge pull request #36 from intrinio/ATS/technical-analysis/VWAP
alexnsolo Mar 19, 2019
d2f4db9
Merge pull request #35 from intrinio/ATS/technical-analysis/README-up…
alexnsolo Mar 19, 2019
ffd9b12
version
alexnsolo Mar 19, 2019
ad17075
Add EMA indicator
nickpellant Feb 26, 2020
7620c8b
updated yard
alexnsolo Feb 27, 2020
2c739d4
Merge pull request #39 from anarkioteam/add-ema-indicator
alexnsolo Feb 27, 2020
210598a
0.2.1
alexnsolo Feb 27, 2020
fa64a6f
Add date_time_key support to EMA indicator
nickpellant Feb 29, 2020
149d838
Add date_time_key support to SMA indicator
nickpellant Feb 29, 2020
ee81300
Update rake requirement from ~> 10.0 to ~> 12.3
dependabot[bot] Feb 29, 2020
91f3518
Merge pull request #40 from anarkioteam/add-date-time-key-param-to-em…
alexnsolo Mar 2, 2020
ea2e052
Merge pull request #41 from intrinio/dependabot/bundler/rake-tw-12.3
alexnsolo Mar 2, 2020
af798a4
bundle
alexnsolo Mar 2, 2020
40a8176
0.2.2
alexnsolo Mar 2, 2020
4f3b04d
+ Weighted Moving Average
thoran Jun 14, 2020
4088e63
+ empty lines as per review
thoran Jun 29, 2020
5236e9f
fix: ~ indicators/adx.rb, so that it works for other than the default…
thoran Jul 31, 2020
1a1dd23
Merge pull request #44 from thoran/thoran/fix/adx
mvonlintel Aug 3, 2020
2ba75f6
0.2.3
mvonlintel Aug 3, 2020
abf8f26
Add date_time_key support to RSI indicator
vertfin Aug 10, 2020
4203453
Merge pull request #45 from vertfin/jms/rsi_date_time_key
alexnsolo Aug 11, 2020
a9482f8
Merge pull request #43 from thoran/thoran/feat/wma
alexnsolo Aug 11, 2020
2c1f3e5
Update README.md
alexnsolo Aug 11, 2020
754fcd2
bundle
alexnsolo Aug 11, 2020
a19eb24
fixed test
alexnsolo Aug 11, 2020
abc776c
Change loop to lookup
ssnyder-intrinio May 19, 2022
5005245
Merge pull request #48 from intrinio/SMS/FixTechsChangeOnPageSize
mvonlintel May 24, 2022
082ce7b
Bump yard from 0.9.25 to 0.9.36
dependabot[bot] Mar 1, 2024
a970433
Merge pull request #52 from intrinio/dependabot/bundler/yard-0.9.36
mvonlintel Mar 1, 2024
bdd7ef0
handle division by zero
jasonl99 Jul 16, 2024
e9efc2c
Merge pull request #53 from intrinio/JML/MFIHandleNegativePeriodFlows
mvonlintel Jul 29, 2024
af8d584
Update README.md
kashrobinson71-tech Sep 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
version: 2
jobs:
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,4 @@ build-iPhoneSimulator/

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc
.tool-versions
37 changes: 37 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
PATH
remote: .
specs:
technical-analysis (0.2.3)

GEM
remote: https://rubygems.org/
specs:
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.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.3)
yard (0.9.36)

PLATFORMS
ruby

DEPENDENCIES
bundler (~> 1.16)
rake (~> 12.3)
rspec (~> 3.0)
technical-analysis!
yard (~> 0.9.20)

BUNDLED WITH
1.17.1
179 changes: 177 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,180 @@
# technical-analysis
# technical-analysisfor codeland
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)
- Exponential Moving Average (EMA)
- 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)
- Volume Weighted Average Price (VWAP)
- Weighted Moving Average (WMA)
- 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
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 }
# ]
```

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.

### 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"

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
```

### 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.calculate('sma', input_data, :indicator_name)
# "Simple Moving Average"

TechnicalAnalysis::Indicator.calculate('sma', input_data, :valid_options)
# [:period, :price_key]

options = { period: 30, price_key: :close }
TechnicalAnalysis::Indicator.calculate('sma', input_data, :validate_options, options)
# true

options = { period: 30, price_key: :close }
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 indicator symbol:

```ruby
simple_moving_average = TechnicalAnalysis::Indicator.find("sma")
# TechnicalAnalysis::Sma

input_data = SpecHelper.get_test_data(:close)
simple_moving_average.calculate(input_data, period: 30, price_key: :close)

simple_moving_average.indicator_symbol
# "sma"

simple_moving_average.indicator_name
# "Simple Moving Average"

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
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`
`rspec spec`
44 changes: 40 additions & 4 deletions lib/technical_analysis.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,44 @@
require "technical_analysis/calculate"

# Helpers
require 'technical_analysis/helpers/array'
require 'technical_analysis/helpers/array_helper'
require 'technical_analysis/helpers/stock_calculation'
require 'technical_analysis/helpers/validation'

# Indicators
require 'technical_analysis/indicators/sma'
require 'technical_analysis/indicators/indicator'

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/ema'
require 'technical_analysis/indicators/eom'
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/vwap'
require 'technical_analysis/indicators/wma'
require 'technical_analysis/indicators/wr'
5 changes: 0 additions & 5 deletions lib/technical_analysis/helpers/array.rb

This file was deleted.

27 changes: 27 additions & 0 deletions lib/technical_analysis/helpers/array_helper.rb
Original file line number Diff line number Diff line change
@@ -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
33 changes: 33 additions & 0 deletions lib/technical_analysis/helpers/stock_calculation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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.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?
ArrayHelper.average(data)
else
(current_value - prev_value) * (2.0 / (period + 1.0)) + 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
ArrayHelper.sum(intermediate_values)
end

end
end
Loading