Technical Analysis Indicator Library

Overview

Provides a wrapper around the talib-ruby library which is a ruby wrapper for the ta-lib library.

This library has been designed to make interfacing with the ta-lib functions easy by wrapping each function in a ruby class.

The wrappers are autogenerated from the xml function description provided with the ta-lib project.

Usage

Requires the talib-ruby gem. The examples require the yahoofinance gem.

Install via gem using:

gem install ta-indicator

Simple Example

The easiest way to use the indicator library is to include the indicator mixin module. This module extends the Array class with the Indicator::Mixin module allowing quick calculations to be performed:

require 'indicator/mixin'
data = [1, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3]
results = data.indicator(:sma, :time_period => 5)
results = data.indicator(:sma, 5)
results = data.indicator(:sma_5)

All perform a simple moving average with time period of 5 and produce the same results:

=> [nil, nil, nil, nil, 2.2, 2.4, 2.6, 2.4, 2.6, 2.4, 2.6]

More complex indicators can also be used

result = data.indicator(:macd_12_26_9)

This performs a macd calculation using a slow period of 12, fast period of 26 and signal period of 9.

The list of available indicators can be retrieved via

Indicator.list

Information about each indicator including a list of arguments can be retrieved via:

Indicator.info :sma
Inficator.info :macd
...

Details

The base Indicator functions are located in the Indicator module and the auto generated classed are located in the Indicator::AutoGen module. All of the following examples assume these modules have been included:

require 'indicator'
include Indicator
include Indicator::AutoGen

Class Construction

All ta-lib functions are wrapped in a class named using the camel class name of the function: SMA is Sma, AVGPRICE is AvgPrice, etc. The constructor takes the optional arguments either as a hash or argument list. For example the Macd class takes three arguments, fast_period, slow_period and signal_period. They can be initialised in any of the following ways:

sma = Sma.new 5
macd = Macd.new 12,26,9

or

sma = Sma.new :time_period => 5
macd = Macd.new :fast_period => 12, :slow_period => 26, :signal_period => 9

If a parameter is not passed in then it will be initialised to the default value as specified by the ta-lib interface.

The Indicator module also supports factory style functions to simplify class creation.

sma = Indicator.create :sma
sma = Indicator.create :sma, 5
sma = Indicator.create :sma, time_period => 5
macd = Indicator.create :macd
macd = Indicator.create :macd, 12,26,9
macd = Indicator.create :macd, :fast_period => 12, :slow_period => 26, :signal_period => 9

If a indicator is to be constructed using only integer parameters then an indicator can be constructed using the create_named factory function. The create_named function expects the indicator name optionally followed by it’s arguments joined by an underscore.

sma = Indicator.create_named :sma_5
macd = Indicator.create_named :macd_12_26_9

Argument attributes

All arguments can be updated through attributes:

macd.fast_period
=> 12
macd.slow_period = 30
=> 30

A list of all the arguments that a particular class takes can be be retrieved using the class method ‘arguments’.

Macd.arguments
=> [:fast_period, :slow_period, :signal_period]
Sma.arguments
=> [:time_period]

Running The Indicators

Each indicator defines a run method that takes in each input array to be processed as a List. An example of an indicator that takes one input:

sma = Indicator.create_named :sma_5
sma.run [1,2,3,4,3,2,3,2,3,2,3,2]
=> [nil, nil, nil, nil, 2.6, 2.8, 3.0, 2.8, 2.6, 2.4, 2.6, 2.4]

An example of an indicator that takes two inputs:

add = Indicator.create_named :add 
add.run [1,2,3,4,5], [5,4,3,2,1]
=> [6.0, 6.0, 6.0, 6.0, 6.0]

Some indicators require OHLC (and optionally V) price inputs. An example of an indicator that takes price inputs:

avg = AvgPrice.new
# AvgPrice run function takes open, high, low, close
avg.run [1,2,1,2], [2,1,2,1], [3,1,3,1], [1,3,1,3]
=> [1.75, 1.75, 1.75, 1.75]

A list of inputs that a indicator run function requires can be retrieved using the class method ‘inputs’.

Sma.inputs
=> [:in_real]
Add.inputs
=> [:in_real0, in_real1] 
AvgPrice.inputs
=> [:open, :high, :low, :close]
AdOsc.inputs
=> [:open, :high, :low, :close, :volume]

Outputs

The run function returns an array containing the results if there is only one List to return otherwise it returns a hash that maps each output List to it’s name. For eample:

sma = Sma.new(5)
sma.run [1,2,3,4,3,2,3,2,3,2,3,2]
=> [nil, nil, nil, nil, 2.6, 2.8, 3.0, 2.8, 2.6, 2.4, 2.6, 2.4]
macd = Macd.new 3,4,1
result = macd.run [1,2,3,4,4,3]
puts results[:out_macd]
=> [nil, nil, -3.785768566076978e-270, 0.5, nil, nil]
puts result[:out_macd_signal]
=> [nil, nil, 0.399999999999999, 0.189999999999999, nil, nil], 
puts result[:out_macd_hist]
=> [nil, nil, -0.3999999999999999, 0.31000000000000005, nil, nil]

A list of outputs that an indicator run function returns can be retrieved using the class method ‘outputs’.

Sma.outputs
=> [:out_real]
Macd.outputs
=> [:out_macd, :out_macd_signal, :out_macd_hist]

Data Mapping

The run function also accepts a DataMapping::Map structure which can be used to extract data from an enumerable collection.

# Assume historical_data is a list of hashes with the following keys
# :open, :high, :low, :close, :volume
sma = Sma.new 5
sma_results = sma.run(DataMapper::Map.new(historical_data, :open))

When the above example is run the DataMapper will attempt to extract data from the historical_data collection by either calling a function called open or retrieving a hash value using the key :open. You can also directly pass in a lambda function if a more complex mapping function is required. To reduce the amount of code required a helper function called new_map is available:

sma = Sma.new 5
sma_results = sma.run new_map(historical_data, :open)
sma_results = sma.run new_map(historical_data, lambda => |b| { b[:open] / 2 })

By default the run function will attempt to use a default getter of :open, so the following is also valid:

sma = Sma.new 5
sma_results = sma.run historical_data 
# Calculates the sma by accessing [:open] on each element of historical_data

The default getter can be changed:

sma = Sma.new 5
sma.default_getter :high
sma_results = sma.run historical_data 
# Calculates the sma by accessing [:high] on each element of historical_data

The same mapping system works for functions requiring price data as an input. The AvgPrice function can be called using either of the following syntax:

ap = AvgPrice.new
ap.run(
  new_map(historical_data, :open), 
  new_map(historical_data, :high), 
  new_map(historical_data, :low), 
  new_map(historical_data, :close))

or

ap = AvgPrice.new
ap.run historical_data

The run function will again attempt to use sensible default mappings of :open, :high, :low, :close and :volume (if required).

Regenerating the wrappers

The wrappers can be regenerated using the gen_wrapper.rb file in the tools directory:

ruby gen_wrapper.rb

This script must be run from the tools directory as it uses realtive paths. The gen_wrapper.rb script uses the erb library to generate code from the defined templates.

Copyright © 2012 Michael Lamb. See LICENSE for details.

The files ta_func_api.xml and ta_func_api.xsd are from the talib library. The license details are contained within LICENSE-ta-lib.