提交
This commit is contained in:
60
backend/tests/test_events.py
Normal file
60
backend/tests/test_events.py
Normal file
@@ -0,0 +1,60 @@
|
||||
"""事件回测纯函数:入场/出场索引语义、汇总统计(含空样本与分年)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from app.backtest.events import _entry_exit_indices, _stats_block
|
||||
from app.schemas import EventBacktestSpec
|
||||
|
||||
|
||||
def _spec(holding_days: int = 5) -> EventBacktestSpec:
|
||||
return EventBacktestSpec.model_validate({
|
||||
"holding_days": holding_days,
|
||||
"entry": {"indicator": []},
|
||||
})
|
||||
|
||||
|
||||
def test_entry_exit_next_day_and_hold():
|
||||
spec = _spec(holding_days=5)
|
||||
assert _entry_exit_indices(10, spec, n=100) == (11, 16) # 次日入,持有 5 日出
|
||||
|
||||
|
||||
def test_entry_exit_out_of_range_none():
|
||||
spec = _spec(holding_days=5)
|
||||
# 出场索引越界(exit_i >= n)
|
||||
assert _entry_exit_indices(94, spec, n=100) is None
|
||||
assert _entry_exit_indices(99, spec, n=100) is None
|
||||
|
||||
|
||||
def test_entry_exit_boundary_exact_fit():
|
||||
spec = _spec(holding_days=5)
|
||||
# exit_i == n-1 恰好可用
|
||||
assert _entry_exit_indices(93, spec, n=100) == (94, 99)
|
||||
|
||||
|
||||
def test_stats_block_empty():
|
||||
s = _stats_block([])
|
||||
assert s["samples"] == 0 and s["stocks"] == 0
|
||||
assert s["by_year"] == []
|
||||
assert s["win_rate"] == 0.0
|
||||
|
||||
|
||||
def test_stats_block_aggregates():
|
||||
trades = [
|
||||
{"ts_code": "000001.SZ", "ret_pct": 10.0,
|
||||
"entry_date": datetime(2024, 1, 5), "entry_price": 10, "exit_price": 11},
|
||||
{"ts_code": "000001.SZ", "ret_pct": -4.0,
|
||||
"entry_date": datetime(2024, 3, 6), "entry_price": 10, "exit_price": 9.6},
|
||||
{"ts_code": "600519.SH", "ret_pct": 2.0,
|
||||
"entry_date": datetime(2023, 5, 10), "entry_price": 10, "exit_price": 10.2},
|
||||
]
|
||||
s = _stats_block(trades)
|
||||
assert s["samples"] == 3
|
||||
assert s["stocks"] == 2
|
||||
assert s["mean_pct"] == pytest.approx((10.0 - 4.0 + 2.0) / 3, abs=1e-3) # 统计块保留 3 位小数
|
||||
assert s["win_rate"] == round(2 / 3 * 100, 2)
|
||||
assert [y["year"] for y in s["by_year"]] == [2023, 2024] # 分年升序
|
||||
assert s["by_year"][1]["samples"] == 2
|
||||
assert s["max_pct"] == 10.0 and s["min_pct"] == -4.0
|
||||
Reference in New Issue
Block a user