Files
ai/backend.old/src/indicator/__init__.py
2026-03-11 18:47:11 -04:00

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",
]