Files
stonks-oracle/tests/test_pbt_risk_tier_defaults.py
T
Celes Renata c85c0068a2 fix: clean up utcnow deprecation warnings, fix 12 failing tests, add CI/CD pipeline manifests
- Replace all datetime.utcnow() with datetime.now(tz=timezone.utc) across 8 files
- Fix 12 failing tests to match current implementation behavior
- Fix pytest_plugins in non-top-level conftest (moved to root conftest.py)
- Auto-fix 189 lint issues (import sorting, unused imports)
- Add CI/CD pipeline infrastructure (ARC, ArgoCD, Kargo manifests)
- Add values-beta.yaml and values-paper.yaml for staged deployments
- Update GitHub Actions workflow to use self-hosted-gremlin runners
- Add integration-test job to CI pipeline

Result: 1596 passed, 0 failed, 0 warnings
2026-04-18 03:59:28 +00:00

169 lines
5.9 KiB
Python

"""Property-based tests for risk tier default parameters.
Feature: autonomous-trading-engine
Validates that the three risk tier defaults (conservative, moderate, aggressive)
have valid parameter ranges and correct ordering relationships.
**Validates: Requirements 5.1**
"""
from __future__ import annotations
from hypothesis import given, settings
from hypothesis import strategies as st
from services.trading.models import RISK_TIER_DEFAULTS, RiskTierConfig
# ---------------------------------------------------------------------------
# Hypothesis strategies
# ---------------------------------------------------------------------------
def _risk_tier_config_strategy() -> st.SearchStrategy[RiskTierConfig]:
"""Generate random RiskTierConfig objects with valid parameter ranges."""
return st.builds(
RiskTierConfig,
name=st.sampled_from(["conservative", "moderate", "aggressive"]),
min_confidence=st.floats(min_value=0.0, max_value=1.0, allow_nan=False),
max_position_pct=st.floats(
min_value=0.01, max_value=1.0, allow_nan=False
),
stop_loss_atr_multiplier=st.floats(
min_value=0.01, max_value=10.0, allow_nan=False
),
reward_risk_ratio=st.floats(
min_value=0.01, max_value=10.0, allow_nan=False
),
max_sector_pct=st.floats(
min_value=0.01, max_value=1.0, allow_nan=False
),
max_portfolio_heat=st.floats(
min_value=0.01, max_value=1.0, allow_nan=False
),
)
# ---------------------------------------------------------------------------
# Property 29 (partial): Risk tier default parameter validation
# ---------------------------------------------------------------------------
EXPECTED_TIERS = {"conservative", "moderate", "aggressive"}
def test_all_three_tiers_exist() -> None:
"""All three risk tiers must be present in RISK_TIER_DEFAULTS.
**Validates: Requirements 5.1**
"""
assert set(RISK_TIER_DEFAULTS.keys()) == EXPECTED_TIERS
def test_each_tier_has_valid_parameter_ranges() -> None:
"""Each tier's parameters must fall within valid ranges.
**Validates: Requirements 5.1**
"""
for tier_name, cfg in RISK_TIER_DEFAULTS.items():
assert cfg.name == tier_name, (
f"Tier name mismatch: key={tier_name}, cfg.name={cfg.name}"
)
# min_confidence in [0, 1]
assert 0.0 <= cfg.min_confidence <= 1.0, (
f"{tier_name}: min_confidence={cfg.min_confidence} not in [0, 1]"
)
# max_position_pct in (0, 1]
assert 0.0 < cfg.max_position_pct <= 1.0, (
f"{tier_name}: max_position_pct={cfg.max_position_pct} not in (0, 1]"
)
# stop_loss_atr_multiplier > 0
assert cfg.stop_loss_atr_multiplier > 0.0, (
f"{tier_name}: stop_loss_atr_multiplier={cfg.stop_loss_atr_multiplier} not > 0"
)
# reward_risk_ratio > 0
assert cfg.reward_risk_ratio > 0.0, (
f"{tier_name}: reward_risk_ratio={cfg.reward_risk_ratio} not > 0"
)
# max_sector_pct in (0, 1]
assert 0.0 < cfg.max_sector_pct <= 1.0, (
f"{tier_name}: max_sector_pct={cfg.max_sector_pct} not in (0, 1]"
)
# max_portfolio_heat in (0, 1]
assert 0.0 < cfg.max_portfolio_heat <= 1.0, (
f"{tier_name}: max_portfolio_heat={cfg.max_portfolio_heat} not in (0, 1]"
)
def test_min_confidence_ordering() -> None:
"""Conservative has highest min_confidence, aggressive has lowest.
conservative.min_confidence > moderate.min_confidence > aggressive.min_confidence
**Validates: Requirements 5.1**
"""
c = RISK_TIER_DEFAULTS["conservative"]
m = RISK_TIER_DEFAULTS["moderate"]
a = RISK_TIER_DEFAULTS["aggressive"]
assert c.min_confidence > m.min_confidence > a.min_confidence, (
f"min_confidence ordering violated: "
f"conservative={c.min_confidence}, "
f"moderate={m.min_confidence}, "
f"aggressive={a.min_confidence}"
)
def test_max_position_pct_ordering() -> None:
"""Conservative has lowest max_position_pct, aggressive has highest.
conservative.max_position_pct < moderate.max_position_pct < aggressive.max_position_pct
**Validates: Requirements 5.1**
"""
c = RISK_TIER_DEFAULTS["conservative"]
m = RISK_TIER_DEFAULTS["moderate"]
a = RISK_TIER_DEFAULTS["aggressive"]
assert c.max_position_pct < m.max_position_pct < a.max_position_pct, (
f"max_position_pct ordering violated: "
f"conservative={c.max_position_pct}, "
f"moderate={m.max_position_pct}, "
f"aggressive={a.max_position_pct}"
)
def test_max_portfolio_heat_ordering() -> None:
"""Conservative has lowest max_portfolio_heat, aggressive has highest.
conservative.max_portfolio_heat < moderate.max_portfolio_heat < aggressive.max_portfolio_heat
**Validates: Requirements 5.1**
"""
c = RISK_TIER_DEFAULTS["conservative"]
m = RISK_TIER_DEFAULTS["moderate"]
a = RISK_TIER_DEFAULTS["aggressive"]
assert c.max_portfolio_heat < m.max_portfolio_heat < a.max_portfolio_heat, (
f"max_portfolio_heat ordering violated: "
f"conservative={c.max_portfolio_heat}, "
f"moderate={m.max_portfolio_heat}, "
f"aggressive={a.max_portfolio_heat}"
)
@settings(max_examples=100)
@given(cfg=_risk_tier_config_strategy())
def test_random_risk_tier_config_parameter_ranges(cfg: RiskTierConfig) -> None:
"""Any randomly generated RiskTierConfig with valid inputs satisfies range invariants.
This property test verifies that the parameter range constraints hold for
arbitrary RiskTierConfig instances, not just the defaults.
**Validates: Requirements 5.1**
"""
assert 0.0 <= cfg.min_confidence <= 1.0
assert 0.0 < cfg.max_position_pct <= 1.0
assert cfg.stop_loss_atr_multiplier > 0.0
assert cfg.reward_risk_ratio > 0.0
assert 0.0 < cfg.max_sector_pct <= 1.0
assert 0.0 < cfg.max_portfolio_heat <= 1.0