Files
ferro-ta/tests/unit/indicators/test_price_transform.py
Pratik Bhadane 307beeca02 release: cut v1.0.0
Prepare the first public 1.0.0 release and finish the remaining CI hardening work.

Highlights:
- align Python, Rust, WASM, Conda, API, MCP, and docs version metadata to 1.0.0
- promote package metadata to Production/Stable and update stability/versioning docs for the stable series
- move the accumulated Unreleased notes into a dated 1.0.0 changelog section and keep a fresh top-level Unreleased block
- strengthen the changelog checker so it validates a single top-level Unreleased section
- fix the CI/package support mismatch by declaring Python >=3.10 consistently and gating pandas-ta extras to Python 3.12+
- restore Sphinx autodoc compatibility for documented ferro_ta.<module> imports by registering module aliases
- make the TA-Lib benchmark guardrail less flaky by checking median and tail-percentile speedups instead of failing on a single mild outlier
- switch PyPI publishing to OIDC-only trusted publishing and wire the changelog check into the required CI gate
- apply the Ruff-driven cleanup across the Python and test tree and refresh uv/cargo lockfiles

Validated locally:
- python3 scripts/check_changelog.py
- uv run --with ruff ruff check python tests
- uv run --with ruff ruff format --check python tests
- uv lock --check
- sphinx-build -b html docs docs/_build -W --keep-going
- build/install the ferro_ta 1.0.0 wheel successfully
2026-03-23 23:57:30 +05:30

114 lines
3.5 KiB
Python

"""Unit tests for ferro_ta.indicators.price_transform"""
import numpy as np
from ferro_ta.indicators.price_transform import AVGPRICE, MEDPRICE, TYPPRICE, WCLPRICE
# ---------------------------------------------------------------------------
# Shared fixtures
# ---------------------------------------------------------------------------
O = np.array([10.0, 11.0, 12.0, 13.0])
H = np.array([12.0, 13.0, 14.0, 15.0])
L = np.array([9.0, 10.0, 11.0, 12.0])
C = np.array([11.0, 12.0, 13.0, 14.0])
# ---------------------------------------------------------------------------
# AVGPRICE
# ---------------------------------------------------------------------------
class TestAVGPRICE:
def test_known_formula(self):
result = AVGPRICE(O, H, L, C)
expected = (O + H + L + C) / 4.0
np.testing.assert_allclose(result, expected, rtol=1e-10)
def test_first_bar(self):
result = AVGPRICE(O, H, L, C)
np.testing.assert_allclose(result[0], (10 + 12 + 9 + 11) / 4.0, rtol=1e-10)
def test_no_nan(self):
result = AVGPRICE(O, H, L, C)
assert np.all(np.isfinite(result))
def test_length(self):
assert len(AVGPRICE(O, H, L, C)) == len(O)
# ---------------------------------------------------------------------------
# MEDPRICE
# ---------------------------------------------------------------------------
class TestMEDPRICE:
def test_known_formula(self):
result = MEDPRICE(H, L)
expected = (H + L) / 2.0
np.testing.assert_allclose(result, expected, rtol=1e-10)
def test_first_bar(self):
result = MEDPRICE(H, L)
np.testing.assert_allclose(result[0], (12 + 9) / 2.0, rtol=1e-10)
def test_no_nan(self):
result = MEDPRICE(H, L)
assert np.all(np.isfinite(result))
def test_length(self):
assert len(MEDPRICE(H, L)) == len(H)
# ---------------------------------------------------------------------------
# TYPPRICE
# ---------------------------------------------------------------------------
class TestTYPPRICE:
def test_known_formula(self):
result = TYPPRICE(H, L, C)
expected = (H + L + C) / 3.0
np.testing.assert_allclose(result, expected, rtol=1e-10)
def test_first_bar(self):
result = TYPPRICE(H, L, C)
np.testing.assert_allclose(result[0], (12 + 9 + 11) / 3.0, rtol=1e-10)
def test_no_nan(self):
result = TYPPRICE(H, L, C)
assert np.all(np.isfinite(result))
def test_length(self):
assert len(TYPPRICE(H, L, C)) == len(H)
# ---------------------------------------------------------------------------
# WCLPRICE
# ---------------------------------------------------------------------------
class TestWCLPRICE:
def test_known_formula(self):
result = WCLPRICE(H, L, C)
expected = (H + L + 2.0 * C) / 4.0
np.testing.assert_allclose(result, expected, rtol=1e-10)
def test_first_bar(self):
result = WCLPRICE(H, L, C)
np.testing.assert_allclose(result[0], (12 + 9 + 2 * 11) / 4.0, rtol=1e-10)
def test_no_nan(self):
result = WCLPRICE(H, L, C)
assert np.all(np.isfinite(result))
def test_close_weight_double(self):
# WCLPRICE weights close twice vs TYPPRICE
wcl = WCLPRICE(H, L, C)
# On a rising series (H > L > 0), WCLPRICE > TYPPRICE when C > (H+L)/2
# Just verify formula correctness already done above
assert np.all(np.isfinite(wcl))
def test_length(self):
assert len(WCLPRICE(H, L, C)) == len(H)