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.

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 :sma_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.