Writing a plugin
The plugin registry lets you register custom indicator functions and call them by name alongside built-in indicators. This page describes the plugin contract, how to register and run plugins, and a full example.
Plugin contract
A plugin is a callable (function or callable object) that satisfies:
Signature - At least one positional argument that is array-like (e.g.
close,high,low). - Optional*argsand**kwargsfor parameters (e.g.timeperiod=14). -ferro_ta.registry.run()forwards all*argsand**kwargsto the callable.Return type - A single
numpy.ndarray, or - A tuple ofnumpy.ndarray(for multi-output indicators). - Output length should match input length (same number of bars); document any exception.Behaviour - The callable may use
ferro_tainternally (e.g. callferro_ta.RSI()and then apply another transformation). - Plugins run with the caller’s privileges; there is no sandboxing.
Validation
ferro_ta.registry.register() checks that the provided object is callable. If not,
it raises TypeError. No strict signature check is performed at registration time
so that valid plugins (e.g. with default arguments) are not rejected.
Step-by-step
Write a function that accepts at least one array-like and returns one or more arrays of the same length as the first argument.
Register it with
ferro_ta.registry.register():from ferro_ta.registry import register register("MY_INDICATOR", my_indicator_function)
Call it by name with
ferro_ta.registry.run():from ferro_ta.registry import run result = run("MY_INDICATOR", close, timeperiod=14)
List all indicators (built-in and registered) with
ferro_ta.registry.list_indicators().
Full example
The following plugin computes a smoothed RSI (RSI of RSI, or “double RSI”) and is
included in the repo as examples/custom_indicator.py:
"""Example plugin: smoothed RSI (RSI applied to RSI values)."""
import numpy as np
from ferro_ta.registry import register, run, list_indicators
from ferro_ta import RSI, SMA
def SMOOTH_RSI(close, timeperiod=14, smooth=3):
"""Smoothed RSI: RSI then SMA of the RSI series."""
rsi = RSI(close, timeperiod=timeperiod)
return SMA(rsi, timeperiod=smooth)
if __name__ == "__main__":
register("SMOOTH_RSI", SMOOTH_RSI)
close = np.array([44.34, 44.09, 44.15, 43.61, 44.33, 44.83, 45.10, 45.15, 44.61, 44.33])
out = run("SMOOTH_RSI", close, timeperiod=5, smooth=2)
print("SMOOTH_RSI:", out)
assert "SMOOTH_RSI" in list_indicators()
API reference
ferro_ta.registry.register()— Register a callable under a name.ferro_ta.registry.unregister()— Remove a registered indicator.ferro_ta.registry.get()— Return the callable for a name.ferro_ta.registry.run()— Look up by name and call with given args/kwargs.ferro_ta.registry.list_indicators()— Sorted list of all registered names.ferro_ta.registry.FerroTARegistryError— Raised when a name is not found.
See ferro_ta.registry for full docstrings.