47 lines
1.4 KiB
Python
47 lines
1.4 KiB
Python
from fxhnt.domain.strategies.equity_factor import (
|
|
momentum_12_1_from_closes,
|
|
realized_vol_from_closes,
|
|
)
|
|
|
|
|
|
def _ramp(n: int, daily: float = 0.001) -> list[float]:
|
|
"""Strictly increasing close series: 100 * (1+daily)**i."""
|
|
return [100.0 * (1.0 + daily) ** i for i in range(n)]
|
|
|
|
|
|
def test_momentum_12_1_positive_for_uptrend():
|
|
closes = _ramp(300)
|
|
m = momentum_12_1_from_closes(closes)
|
|
assert m is not None and m > 0.0
|
|
|
|
|
|
def test_momentum_12_1_none_when_insufficient_history():
|
|
assert momentum_12_1_from_closes(_ramp(50)) is None
|
|
|
|
|
|
def test_momentum_12_1_none_when_recent_price_nonpositive():
|
|
closes = _ramp(300)
|
|
closes[-21] = 0.0 # the "recent" (skip) price is non-positive
|
|
assert momentum_12_1_from_closes(closes) is None
|
|
|
|
|
|
def test_momentum_12_1_none_when_lookback_price_nonpositive():
|
|
closes = _ramp(300)
|
|
closes[-252] = 0.0 # the lookback base price is non-positive
|
|
assert momentum_12_1_from_closes(closes) is None
|
|
|
|
|
|
def test_realized_vol_zero_for_constant_series():
|
|
v = realized_vol_from_closes([100.0] * 120)
|
|
assert v is not None and v == 0.0
|
|
|
|
|
|
def test_realized_vol_positive_for_wiggly_series():
|
|
closes = [100.0 * (1.0 + (0.02 if i % 2 == 0 else -0.02)) for i in range(120)]
|
|
v = realized_vol_from_closes(closes)
|
|
assert v is not None and v > 0.0
|
|
|
|
|
|
def test_realized_vol_none_when_insufficient_history():
|
|
assert realized_vol_from_closes([100.0] * 5) is None
|