Coverage for src/tinycta/ewma.py: 100%
3 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-06 05:36 +0000
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-06 05:36 +0000
1"""EWMA-based signal generation utilities.
3This module exposes helpers built around exponentially weighted moving averages
4(EWMA) for use inside Polars expression pipelines. Functions operate column-
5wise and are suitable for DataFrame.with_columns usage in notebooks and batch
6pipelines.
7"""
9import polars as pl
12def ma_cross(prices: pl.Expr, fast: int, slow: int, min_samples: int = 1) -> pl.Expr:
13 """Return the sign of the fast-vs-slow EWM moving-average cross per column.
15 Computes two exponentially weighted moving averages (EWM) of the input
16 price series using windows ``fast`` and ``slow`` (interpreted as
17 ``com=window-1``) and returns the sign of their difference. The output
18 is -1, 0, or +1 after the warmup implied by ``min_samples``.
20 Args:
21 prices: Polars expression containing the price series to transform.
22 fast: Length for the fast EWM mean (``fast > 0``). Typically ``fast < slow``.
23 slow: Length for the slow EWM mean (``slow > 0``).
24 min_samples: Minimum number of observations required before EWM values
25 are produced; earlier rows will be null.
27 Returns:
28 pl.Expr: An expression yielding -1, 0, or +1 per row after warmup.
30 Example:
31 >>> prices = pl.DataFrame({"A": [1,2,3,4,5,6,7,8,9,10]})
32 >>> df = prices.with_columns(
33 ... ma_cross(pl.col("A"), fast=2, slow=6, min_samples=3).alias("sig_A")
34 ... )
35 """
36 return (
37 prices.ewm_mean(com=fast - 1, adjust=False, min_samples=min_samples)
38 - prices.ewm_mean(com=slow - 1, adjust=False, min_samples=min_samples)
39 ).sign()