diff --git a/indicators/test_bollinger.py b/indicators/test_bollinger.py new file mode 100644 index 000000000..1b31e73c2 --- /dev/null +++ b/indicators/test_bollinger.py @@ -0,0 +1,89 @@ +""" +Bollinger Bands 单元测试 + +Author: 张飞 翼德 +Date: 2026-05-31 +""" + +import math +from bollinger import calc_bollinger + + +def test_basic(): + """基本功能测试""" + prices = [float(10 + i) for i in range(25)] + upper, middle, lower = calc_bollinger(prices, period=5) + assert len(upper) == 21 # 25 - 5 + 1 + assert len(middle) == 21 + assert len(lower) == 21 + + +def test_sma_correctness(): + """验证 middle 等于 SMA""" + prices = [10.0, 11.0, 12.0, 13.0, 14.0] + upper, middle, lower = calc_bollinger(prices, period=3) + # SMA of [10,11,12] = 11.0 + assert math.isclose(middle[0], 11.0) + # SMA of [11,12,13] = 12.0 + assert math.isclose(middle[1], 12.0) + # SMA of [12,13,14] = 13.0 + assert math.isclose(middle[2], 13.0) + + +def test_upper_lower_symmetry(): + """验证上下轨关于中轨对称""" + prices = [float(44 + i * 0.5 + (i % 3) * 0.2) for i in range(30)] + upper, middle, lower = calc_bollinger(prices, period=10) + for u, m, l in zip(upper, middle, lower): + assert math.isclose(u - m, m - l, rel_tol=1e-9) + + +def test_upper_gt_middle_gt_lower(): + """上轨 > 中轨 > 下轨""" + prices = [10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0] + upper, middle, lower = calc_bollinger(prices, period=5) + for u, m, l in zip(upper, middle, lower): + assert u > m > l + + +def test_num_std_zero(): + """num_std=0 → 三条线重合""" + prices = [10.0, 11.0, 12.0, 13.0, 14.0] + upper, middle, lower = calc_bollinger(prices, period=3, num_std=0.0) + for u, m, l in zip(upper, middle, lower): + assert math.isclose(u, m) + assert math.isclose(m, l) + + +def test_insufficient_data(): + """数据不足 → 空列表""" + prices = [10.0, 11.0, 12.0] + upper, middle, lower = calc_bollinger(prices, period=5) + assert upper == [] and middle == [] and lower == [] + + +def test_period_invalid(): + """period <= 0""" + prices = [10.0, 11.0, 12.0] + upper, middle, lower = calc_bollinger(prices, period=0) + assert upper == [] and middle == [] and lower == [] + upper, middle, lower = calc_bollinger(prices, period=-1) + assert upper == [] and middle == [] and lower == [] + + +def test_empty_input(): + """空输入""" + upper, middle, lower = calc_bollinger([], period=5) + assert upper == [] and middle == [] and lower == [] + + +if __name__ == "__main__": + test_basic() + test_sma_correctness() + test_upper_lower_symmetry() + test_upper_gt_middle_gt_lower() + test_num_std_zero() + test_insufficient_data() + test_period_invalid() + test_empty_input() + print("所有测试通过 ✅")