feat: add fundamentals weighting backtest research
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import math
|
||||
|
||||
import pytest
|
||||
|
||||
from app.services import fundamentals_research as research
|
||||
|
||||
|
||||
def test_favorable_percentiles_are_tie_aware():
|
||||
ranks = research.favorable_percentiles(
|
||||
{"a": 3, "b": 3, "c": 3, "d": 3, "e": 3},
|
||||
higher_is_better=True,
|
||||
)
|
||||
assert set(ranks.values()) == {50.0}
|
||||
|
||||
|
||||
def test_lower_is_better_flips_the_rank():
|
||||
ranks = research.favorable_percentiles(
|
||||
{"a": 1, "b": 2, "c": 3, "d": 4, "e": 5},
|
||||
higher_is_better=False,
|
||||
)
|
||||
assert ranks["a"] == 100.0
|
||||
assert ranks["e"] == 0.0
|
||||
|
||||
|
||||
def test_invalid_and_thin_cross_sections_stay_null():
|
||||
ranks = research.favorable_percentiles(
|
||||
{"a": 1, "b": 2, "c": math.nan, "d": None, "e": 5},
|
||||
higher_is_better=True,
|
||||
)
|
||||
assert all(value is None for value in ranks.values())
|
||||
|
||||
|
||||
def test_composites_use_equal_subgroup_weighting():
|
||||
features = {
|
||||
str(index): {
|
||||
"operating_margin": index,
|
||||
"fcf_margin": index,
|
||||
"net_debt_to_ebitda": 6 - index,
|
||||
"share_count_change_yoy": 6 - index,
|
||||
"revenue_growth_yoy": index,
|
||||
"eps_growth_yoy": index,
|
||||
}
|
||||
for index in range(1, 6)
|
||||
}
|
||||
scores = research.cross_section_scores(features)
|
||||
assert scores["5"]["quality"] == 100.0
|
||||
assert scores["5"]["growth"] == 100.0
|
||||
assert scores["5"]["balanced"] == 100.0
|
||||
assert scores["3"]["balanced"] == 50.0
|
||||
|
||||
|
||||
def test_overlay_uses_neutral_missing_score_and_validates_weight():
|
||||
assert research.overlay_rank(90, None, 0.2) == 82.0
|
||||
assert research.overlay_rank(90, 100, 0.2) == 92.0
|
||||
with pytest.raises(ValueError, match="weight"):
|
||||
research.overlay_rank(90, 50, 1.1)
|
||||
Reference in New Issue
Block a user