42 lines
1.6 KiB
Python
42 lines
1.6 KiB
Python
import numpy as np
|
|
|
|
from fxhnt.application.forward_recompute import derive_nav, recompute_series
|
|
|
|
|
|
class _FakeStrategy:
|
|
def __init__(self, series):
|
|
self._series = series
|
|
|
|
def advance(self, last_date, extra):
|
|
return list(self._series), extra
|
|
|
|
|
|
def test_recompute_filters_to_since_t0():
|
|
strat = _FakeStrategy([("2026-07-06", 0.01), ("2026-07-07", 0.02), ("2026-07-08", -0.01)])
|
|
assert recompute_series(strat, "2026-07-07") == [("2026-07-07", 0.02), ("2026-07-08", -0.01)]
|
|
|
|
|
|
def test_recompute_is_deterministic():
|
|
strat = _FakeStrategy([("2026-07-07", 0.02), ("2026-07-06", 0.01)]) # unsorted input
|
|
a = recompute_series(strat, "2026-07-01")
|
|
b = recompute_series(strat, "2026-07-01")
|
|
assert a == b == [("2026-07-06", 0.01), ("2026-07-07", 0.02)] # sorted, both runs identical
|
|
|
|
|
|
def test_derive_nav_matches_forward_tracker_formula():
|
|
rows = [("2026-07-06", 0.01), ("2026-07-07", 0.02), ("2026-07-08", -0.01)]
|
|
nav_rows, summary = derive_nav(rows)
|
|
# nav compounds
|
|
assert abs(nav_rows[-1][1] - (1.01 * 1.02 * 0.99)) < 1e-12
|
|
assert summary["days"] == 3
|
|
assert abs(summary["nav"] - 1.01 * 1.02 * 0.99) < 1e-12
|
|
# sharpe uses per_period_sharpe * sqrt(365) for >=3 rows
|
|
from fxhnt.domain.gauntlet import per_period_sharpe
|
|
exp = float(per_period_sharpe(np.array([0.01, 0.02, -0.01])) * np.sqrt(365.0))
|
|
assert abs(summary["sharpe"] - exp) < 1e-9
|
|
|
|
|
|
def test_derive_nav_empty_is_wait_safe():
|
|
nav_rows, summary = derive_nav([])
|
|
assert nav_rows == [] and summary["days"] == 0 and summary["nav"] == 1.0 and summary["last_date"] is None
|