85 lines
3.0 KiB
Python
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) # 月初
|