Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![CI/CD](https://img.shields.io/badge/CI%2FCD-passing-brightgreen)](https://github.com/OnePunchMonk/AgentQuant/actions)
![Python](https://img.shields.io/badge/python-3.10%2B-blue)
![Tests](https://img.shields.io/badge/tests-191%20passed-brightgreen)
![Tests](https://img.shields.io/badge/tests-196%20passed-brightgreen)
![Last Updated](https://img.shields.io/badge/last%20updated-2026--09--22-blue)

> **AgentQuant does not just search for trading strategies; it evolves how it searches for them.**
Expand Down
54 changes: 54 additions & 0 deletions tests/test_momentum_legacy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
"""Tests for the backward-compatible src.strategies.momentum wrapper."""

import numpy as np
import pandas as pd
import pytest

Check failure on line 5 in tests/test_momentum_legacy.py

View workflow job for this annotation

GitHub Actions / Test Suite (Python 3.12)

ruff (F401)

tests/test_momentum_legacy.py:5:8: F401 `pytest` imported but unused help: Remove unused import: `pytest`

Check failure on line 5 in tests/test_momentum_legacy.py

View workflow job for this annotation

GitHub Actions / Test Suite (Python 3.10)

ruff (F401)

tests/test_momentum_legacy.py:5:8: F401 `pytest` imported but unused help: Remove unused import: `pytest`

Check failure on line 5 in tests/test_momentum_legacy.py

View workflow job for this annotation

GitHub Actions / Test Suite (Python 3.11)

ruff (F401)

tests/test_momentum_legacy.py:5:8: F401 `pytest` imported but unused help: Remove unused import: `pytest`

from src.strategies.momentum import create_momentum_signals


def _make_close_series(n: int = 300, trend: float = 0.001, seed: int = 0) -> pd.Series:
rng = np.random.default_rng(seed)
close = 100 * np.cumprod(1 + rng.normal(trend, 0.01, n))
idx = pd.date_range("2020-01-01", periods=n)
return pd.Series(close, index=idx, name="Close")


def test_accepts_series_input():
close = _make_close_series()
entries, exits = create_momentum_signals(close)
assert isinstance(entries, pd.Series)
assert isinstance(exits, pd.Series)
assert len(entries) == len(close)
assert len(exits) == len(close)


def test_accepts_dataframe_input():
close = _make_close_series()
df = close.to_frame("Close")
entries, exits = create_momentum_signals(df)
assert len(entries) == len(df)
assert len(exits) == len(df)


def test_entries_and_exits_are_boolean_and_mutually_exclusive():
close = _make_close_series(trend=0.002)
entries, exits = create_momentum_signals(close)
assert entries.dtype == bool
assert exits.dtype == bool
assert not (entries & exits).any()


def test_custom_windows_are_respected():
close = _make_close_series(n=400, seed=7)
entries_a, exits_a = create_momentum_signals(close, fast_window=5, slow_window=20)
entries_b, exits_b = create_momentum_signals(close, fast_window=21, slow_window=63)
assert not entries_a.equals(entries_b) or not exits_a.equals(exits_b)


def test_flat_series_produces_no_signals():
idx = pd.date_range("2020-01-01", periods=100)
close = pd.Series(100.0, index=idx)
entries, exits = create_momentum_signals(close)
assert not entries.any()
assert not exits.any()
Loading