Implement New Indicator
Scope
Use this skill when the user asks to implement a new strategy indicator in TradePy.
Core rules from the project:
- Implementations go into
tradepy/strategy/indicators.py - Use
_fast_ewmfor exponential weighted averages. We deliberately avoid Wilder's Smoothing due to its complexity, and instead use Polars' built-inewm_meanfor best performance. As a result, more leading bars need to be discarded during warmup. - For each new indicator implemented, verify it against TA-Lib. The dev dependency already includes TA-Lib. You need to confirm that the calculated indicator values converge with TA-Lib's results.
Implementation Workflow
- Read
tradepy/strategy/indicators.py,tradepy/strategy/__init__.py, and relevant tests before editing. - Add the indicator as a typed
@dataclass(frozen=True)subclass ofSeriesIndicatorand implementcompute(self, value: pl.Expr). The base class resolves the input: at the pipeline root,valueis the adjustedcolumnprice; otherwise it is the upstream pipeline output. - Follow the existing output style:
- Return
pl.Exprfor single-output indicators. - Return
dict[str, pl.Expr]for multi-output indicators that requireTake(...). - Set
requires_upstream: ClassVar[bool] = Truefor transforms that are meaningless without a piped input (e.g.Lag).
- Return
- For exponential weighted averages, use
_fast_ewm(...)and set a warmup long enough for convergence against TA-Lib. Declare the warmup multiplier as aWARMUP_FACTOR: ClassVar[int]on the indicator class. - Export the indicator from
tradepy/strategy/__init__.py. - Add focused pytest coverage in
tests/test_indicators.py.
TA-Lib Verification
Tests must compare the new Polars indicator against the matching TA-Lib function and prove convergence after warmup.
Use a deterministic price series with enough rows for convergence, then compare only the non-null tail:
import numpy as np
import talib
def test_new_indicator_converges_with_talib() -> None:
close = np.linspace(10.0, 200.0, 300)
# Build a Polars DataFrame and compute the project indicator.
# Compute the TA-Lib reference with the same period/configuration.
# Drop leading null/NaN values and assert the tail converges.
Prefer pytest.approx(...) or numpy.testing.assert_allclose(...) with tolerances that reflect floating-point convergence rather than exact equality.
Commands
Use uv for verification:
uv run pytest tests/test_indicators.py
If type or lint behavior is relevant to the change, also run the existing project commands for pyright or ruff.
Source: namoshizun/TradePy — distributed by TomeVault.