Files
sanguo_vnpy_v2/tests/shadow_desk/test_spike_p0_compare.py
T

85 lines
3.0 KiB
Python

"""P0 对账 spike 的纯逻辑测试(compare / _auto_splits)。
跑真实数据的对账在 VPS 上执行(见 scripts/shadow_desk/spike_p0_checkpoint_replay.py)。
"""
from __future__ import annotations
import importlib.util
import sys
from pathlib import Path
import pytest
_SPEC = importlib.util.spec_from_file_location(
"spike_p0",
Path(__file__).resolve().parents[2] / "scripts" / "shadow_desk" / "spike_p0_checkpoint_replay.py",
)
spike = importlib.util.module_from_spec(_SPEC)
sys.modules.setdefault("spike_p0", spike)
_SPEC.loader.exec_module(spike)
def _full(consistency: str = "same") -> dict:
if consistency == "same":
positions = [{"security": "600519.SH", "amount": 100, "avg_cost": 1700.5, "price": 1750.0}]
cash, total = 820_000.0, 995_000.0
equity = [("2024-01-05", 1_000_000.0), ("2024-02-01", 1_010_000.0)]
elif consistency == "amount_diff":
positions = [{"security": "600519.SH", "amount": 200, "avg_cost": 1700.5, "price": 1750.0}]
cash, total = 820_000.0, 995_000.0
equity = [("2024-01-05", 1_000_000.0), ("2024-02-01", 1_010_000.0)]
else: # equity_drift
positions = [{"security": "600519.SH", "amount": 100, "avg_cost": 1700.5, "price": 1750.0}]
cash, total = 820_000.0, 995_000.0
equity = [("2024-01-05", 1_000_000.0), ("2024-02-01", 1_010_500.0)]
return {
"final_portfolio": {"cash": cash, "total_value": total, "positions": positions},
"equity_curve": [{"date": d, "equity": v} for d, v in equity],
}
def _seg() -> dict:
return {
"final_portfolio": {
"cash": 820_000.000_000_4, # 浮点级噪声
"total_value": 995_000.0,
"positions": [{"security": "600519.SH", "amount": 100,
"avg_cost": 1700.500_000_1, "price": 1750.0}],
},
"equity_curve": [{"date": "2024-01-05", "equity": 1_000_000.0},
{"date": "2024-02-01", "equity": 1_010_000.0}],
}
def test_compare_pass_on_float_noise():
assert spike.compare(_full(), _seg()) == []
def test_compare_catches_amount_diff():
problems = spike.compare(_full("amount_diff"), _seg())
assert any("数量" in p for p in problems)
def test_compare_catches_equity_drift():
problems = spike.compare(_full("equity_drift"), _seg())
assert any("净值曲线最大偏差" in p for p in problems)
def test_compare_catches_missing_position():
seg = _seg()
seg["final_portfolio"]["positions"] = []
problems = spike.compare(_full(), seg)
assert any("单边缺失" in p for p in problems)
def test_compare_catches_missing_final_portfolio():
problems = spike.compare({"equity_curve": []}, _seg())
assert problems and "final_portfolio" in problems[0]
def test_auto_splits_month_first_and_ascending():
splits = spike._auto_splits("2024-01-01", "2024-12-31")
assert len(splits) == 2
assert splits[0] < splits[1]
assert all(s.endswith("-01") for s in splits) # 月初