This commit is contained in:
2026-09-09 15:07:58 +08:00
parent d656c05b3d
commit 71a0f6e404
31 changed files with 3657 additions and 9 deletions

View File

@@ -0,0 +1,65 @@
"""复权换算 adjust_barsbfq/qfq/hfq 乘数、阶梯因子向前沿用、名义量不缩放。"""
from __future__ import annotations
from datetime import datetime
import pytest
from app.api._deps import adjust_bars
from app.domain import Bar
def _bars(*rows) -> list[Bar]:
# (date, open, close)
return [Bar(ts=datetime(y, m, d), open=o, high=o, low=o, close=c, volume=100.0)
for (y, m, d), o, c in rows]
def _factors(*pairs):
return [(datetime(y, m, d), f) for (y, m, d), f in pairs]
def test_bfq_to_bfq_identity():
bars = _bars(((2024, 1, 2), 10.0, 11.0))
out = adjust_bars(bars, _factors(((2024, 1, 2), 2.0)), "bfq", "bfq")
assert out[0].close == 11.0
def test_qfq_normalizes_by_latest_factor():
# 因子 1.0 -> 2.0中途除权qfq = f(t)/f(latest)
bars = _bars(
((2024, 1, 2), 10.0, 10.0), # f=1.0
((2024, 6, 3), 5.0, 5.0), # f=2.0(除权日,价格腰斩)
)
factors = _factors(((2024, 1, 2), 1.0), ((2024, 6, 3), 2.0))
out = adjust_bars(bars, factors, "bfq", "qfq")
# 除权前按 1.0/2.0 缩放 -> 5.0;除权后 2.0/2.0 -> 原价
assert out[0].close == pytest.approx(5.0)
assert out[1].close == pytest.approx(5.0)
def test_hfq_scales_by_factor():
bars = _bars(((2024, 1, 2), 10.0, 10.0), ((2024, 6, 3), 5.0, 5.0))
factors = _factors(((2024, 1, 2), 1.0), ((2024, 6, 3), 2.0))
out = adjust_bars(bars, factors, "bfq", "hfq")
assert out[0].close == pytest.approx(10.0) # f=1
assert out[1].close == pytest.approx(10.0) # 5 * 2
def test_factor_step_forward_fill():
"""因子是阶梯函数:变化点之间的日期向前沿用最近因子。"""
bars = _bars(((2024, 2, 1), 8.0, 8.0)) # 在 1/2 与 6/3 之间 -> 沿用 1.0
factors = _factors(((2024, 1, 2), 1.0), ((2024, 6, 3), 2.0))
out = adjust_bars(bars, factors, "bfq", "hfq")
assert out[0].close == pytest.approx(8.0) # 8 * 1.0
def test_nominal_columns_not_scaled():
"""成交额/换手率是名义量,不随复权缩放。"""
bars = [Bar(ts=datetime(2024, 1, 2), open=10, high=10, low=10, close=10,
volume=100.0, amount=1_000_000.0, turnover=1.5)]
out = adjust_bars(bars, _factors(((2024, 1, 2), 4.0)), "bfq", "hfq")
assert out[0].close == pytest.approx(40.0)
assert out[0].amount == 1_000_000.0
assert out[0].turnover == 1.5
assert out[0].volume == 100.0