180 lines
5.5 KiB
Python
180 lines
5.5 KiB
Python
"""
|
|
Composable Indicator System.
|
|
|
|
Provides a framework for building DAGs of data transformation pipelines
|
|
that process time-series data incrementally. Indicators can consume
|
|
DataSources or other Indicators as inputs, composing into arbitrarily
|
|
complex processing graphs.
|
|
|
|
Key Components:
|
|
---------------
|
|
|
|
Indicator (base.py):
|
|
Abstract base class for all indicator implementations.
|
|
Declares input/output schemas and implements synchronous compute().
|
|
|
|
IndicatorRegistry (registry.py):
|
|
Central catalog of available indicators with rich metadata
|
|
for AI agent discovery and tool generation.
|
|
|
|
Pipeline (pipeline.py):
|
|
Execution engine that builds DAGs, resolves dependencies,
|
|
and orchestrates incremental data flow through indicator chains.
|
|
|
|
Schema Types (schema.py):
|
|
Type definitions for input/output schemas, computation context,
|
|
and metadata for AI-native documentation.
|
|
|
|
Usage Example:
|
|
--------------
|
|
|
|
from indicator import Indicator, IndicatorRegistry, Pipeline
|
|
from indicator.schema import (
|
|
InputSchema, OutputSchema, ComputeContext, ComputeResult,
|
|
IndicatorMetadata, IndicatorParameter
|
|
)
|
|
|
|
# Define an indicator
|
|
class SimpleMovingAverage(Indicator):
|
|
@classmethod
|
|
def get_metadata(cls):
|
|
return IndicatorMetadata(
|
|
name="SMA",
|
|
display_name="Simple Moving Average",
|
|
description="Arithmetic mean of prices over N periods",
|
|
category="trend",
|
|
parameters=[
|
|
IndicatorParameter(
|
|
name="period",
|
|
type="int",
|
|
description="Number of periods to average",
|
|
default=20,
|
|
min_value=1
|
|
)
|
|
],
|
|
tags=["moving-average", "trend-following"]
|
|
)
|
|
|
|
@classmethod
|
|
def get_input_schema(cls):
|
|
return InputSchema(
|
|
required_columns=[
|
|
ColumnInfo(name="close", type="float", description="Closing price")
|
|
]
|
|
)
|
|
|
|
@classmethod
|
|
def get_output_schema(cls, **params):
|
|
return OutputSchema(
|
|
columns=[
|
|
ColumnInfo(
|
|
name="sma",
|
|
type="float",
|
|
description=f"Simple moving average over {params.get('period', 20)} periods"
|
|
)
|
|
]
|
|
)
|
|
|
|
def compute(self, context: ComputeContext) -> ComputeResult:
|
|
period = self.params["period"]
|
|
closes = context.get_column("close")
|
|
times = context.get_times()
|
|
|
|
sma_values = []
|
|
for i in range(len(closes)):
|
|
if i < period - 1:
|
|
sma_values.append(None)
|
|
else:
|
|
window = closes[i - period + 1 : i + 1]
|
|
sma_values.append(sum(window) / period)
|
|
|
|
return ComputeResult(
|
|
data=[
|
|
{"time": times[i], "sma": sma_values[i]}
|
|
for i in range(len(times))
|
|
]
|
|
)
|
|
|
|
# Register the indicator
|
|
registry = IndicatorRegistry()
|
|
registry.register(SimpleMovingAverage)
|
|
|
|
# Create a pipeline
|
|
pipeline = Pipeline(datasource_registry)
|
|
pipeline.add_datasource("price_data", "ccxt", "BTC/USD", "1D")
|
|
|
|
sma_indicator = registry.create_instance("SMA", "sma_20", period=20)
|
|
pipeline.add_indicator("sma_20", sma_indicator, input_node_ids=["price_data"])
|
|
|
|
# Execute
|
|
results = pipeline.execute(datasource_data={"price_data": price_bars})
|
|
sma_output = results["sma_20"] # Contains columns: time, close, sma_20_sma
|
|
|
|
Design Philosophy:
|
|
------------------
|
|
|
|
1. **Schema-based composition**: Indicators declare inputs/outputs via schemas,
|
|
enabling automatic validation and flexible composition.
|
|
|
|
2. **Synchronous execution**: All computation is synchronous for simplicity.
|
|
Async handling happens at the event/strategy layer.
|
|
|
|
3. **Incremental updates**: Indicators receive context about what changed,
|
|
allowing optimized recomputation of only affected values.
|
|
|
|
4. **AI-native metadata**: Rich descriptions, use cases, and parameter specs
|
|
make indicators discoverable and usable by AI agents.
|
|
|
|
5. **Generic data flow**: Indicators work with any data source that matches
|
|
their input schema, not specific DataSource instances.
|
|
|
|
6. **Event-driven**: Designed to react to DataSource updates and propagate
|
|
changes through the DAG efficiently.
|
|
"""
|
|
|
|
from .base import DataSourceAdapter, Indicator
|
|
from .pipeline import Pipeline, PipelineNode
|
|
from .registry import IndicatorRegistry
|
|
from .schema import (
|
|
ComputeContext,
|
|
ComputeResult,
|
|
IndicatorMetadata,
|
|
IndicatorParameter,
|
|
InputSchema,
|
|
OutputSchema,
|
|
)
|
|
from .talib_adapter import (
|
|
TALibIndicator,
|
|
register_all_talib_indicators,
|
|
is_talib_available,
|
|
get_talib_version,
|
|
)
|
|
from .custom_indicators import (
|
|
register_custom_indicators,
|
|
CUSTOM_INDICATORS,
|
|
)
|
|
|
|
__all__ = [
|
|
# Core classes
|
|
"Indicator",
|
|
"IndicatorRegistry",
|
|
"Pipeline",
|
|
"PipelineNode",
|
|
"DataSourceAdapter",
|
|
# Schema types
|
|
"InputSchema",
|
|
"OutputSchema",
|
|
"ComputeContext",
|
|
"ComputeResult",
|
|
"IndicatorMetadata",
|
|
"IndicatorParameter",
|
|
# TA-Lib integration
|
|
"TALibIndicator",
|
|
"register_all_talib_indicators",
|
|
"is_talib_available",
|
|
"get_talib_version",
|
|
# Custom indicators
|
|
"register_custom_indicators",
|
|
"CUSTOM_INDICATORS",
|
|
]
|