Files
group_fqcd_jr/tests/unit/service/test_allocation_backtest_service.py
T

71 lines
2.5 KiB
Python
Raw Normal View History

2026-09-11 14:59:16 +08:00
from datetime import date, timedelta
from decimal import Decimal
from app.service.allocation_backtest_service import (
AllocationBacktestEngine,
AllocationBacktestService,
BacktestObservation,
)
def observation(day: int, cash: str, equity: str, liquid: bool = True) -> BacktestObservation:
return BacktestObservation(
trade_date=date(2026, 1, 1) + timedelta(days=day),
returns_pct={
"cash_management_etf": Decimal(cash),
"equity_etf": Decimal(equity),
},
liquidity_observed=liquid,
)
def test_backtest_compares_static_and_dynamic_performance() -> None:
observations = [observation(0, "0", "10"), observation(1, "0", "-10")]
result = AllocationBacktestEngine.run(
observations,
{"cash_management_etf": 50, "bond_etf": 0, "equity_etf": 50},
{
observations[1].trade_date: {
"cash_management_etf": 100,
"bond_etf": 0,
"equity_etf": 0,
}
},
)
assert result.observation_count == 2
assert result.static is not None and result.dynamic is not None
assert result.static.total_return_pct == Decimal("-0.2500")
assert result.dynamic.total_return_pct == Decimal("5.0000")
assert result.dynamic_rebalance_count == 1
assert result.liquidity_history_coverage_pct == Decimal("100")
assert result.status == "insufficient_history"
def test_rolling_metrics_and_adequate_history_are_ready() -> None:
observations = [observation(day, "1", "2") for day in range(20)]
metrics = AllocationBacktestService._rolling_metrics(observations)
assert {item.asset_class for item in metrics} == {"cash_management_etf", "equity_etf"}
assert all(item.product_count == 20 for item in metrics)
result = AllocationBacktestEngine.run(
observations,
{"cash_management_etf": 50, "bond_etf": 0, "equity_etf": 50},
{},
)
assert result.status == "ready"
assert result.limitations == ("历史观察不足 120 个交易日,动态优化无法覆盖完整窗口。",)
def test_backtest_reports_liquidity_coverage_limit() -> None:
observations = [observation(day, "0", "0", day < 10) for day in range(20)]
result = AllocationBacktestEngine.run(
observations,
{"cash_management_etf": 100, "bond_etf": 0, "equity_etf": 0},
{},
)
assert result.status == "partial"
assert result.liquidity_history_coverage_pct == Decimal("50")
assert any("80%" in limitation for limitation in result.limitations)