154 lines
4.9 KiB
Python
154 lines
4.9 KiB
Python
"""A 股涨跌停纯函数测试(板块表 + 封板判断)。全用 raw 价格。"""
|
||
import pandas as pd
|
||
|
||
from sanguo_trader.limit import (
|
||
get_board,
|
||
limit_ratio,
|
||
limit_up_price,
|
||
limit_down_price,
|
||
is_one_word_lock,
|
||
is_t_lock,
|
||
is_locked_for_buy_symbol,
|
||
is_locked_for_sell_symbol,
|
||
)
|
||
from sanguo_trader.models import AccountConfig
|
||
|
||
CFG = AccountConfig(initial_capital=1_000_000)
|
||
|
||
|
||
def bar(open, high, low, close):
|
||
return pd.Series({"open": open, "high": high, "low": low, "close": close})
|
||
|
||
|
||
# ---- 板块分类 ----
|
||
def test_board_classification():
|
||
assert get_board("600000") == "main" # 沪市主板
|
||
assert get_board("000001") == "main" # 深市主板
|
||
assert get_board("300750") == "gem" # 创业板
|
||
assert get_board("301128") == "gem" # 创业板(301)
|
||
assert get_board("688981") == "star" # 科创板
|
||
assert get_board("689009") == "star" # 科创板(689)
|
||
assert get_board("830799") == "bse" # 北交所
|
||
assert get_board("920002") == "bse" # 北交所(920)
|
||
|
||
|
||
# ---- 幅度查表 ----
|
||
def test_limit_ratio():
|
||
assert limit_ratio("main", is_st=False) == 0.10
|
||
assert limit_ratio("gem", is_st=False) == 0.20
|
||
assert limit_ratio("star", is_st=False) == 0.20
|
||
assert limit_ratio("bse", is_st=False) == 0.30
|
||
# ST 统一 5%
|
||
assert limit_ratio("main", is_st=True) == 0.05
|
||
assert limit_ratio("gem", is_st=True) == 0.05
|
||
assert limit_ratio("star", is_st=True) == 0.05
|
||
assert limit_ratio("bse", is_st=True) == 0.30 # 北交所 ST 同 30%
|
||
|
||
|
||
# ---- 涨跌停价(按 pricetick 取整)----
|
||
def test_limit_up_price_rounds_to_pricetick():
|
||
# 10.00 * 1.10 = 11.00
|
||
assert limit_up_price(10.0, 0.10, 0.01) == 11.0
|
||
# 9.99 * 1.20 = 11.988 → 11.99
|
||
assert limit_up_price(9.99, 0.20, 0.01) == 11.99
|
||
# 5.00 * 1.30 = 6.5
|
||
assert limit_up_price(5.0, 0.30, 0.01) == 6.5
|
||
|
||
|
||
def test_limit_down_price_rounds_to_pricetick():
|
||
# 10.00 * 0.90 = 9.00
|
||
assert limit_down_price(10.0, 0.10, 0.01) == 9.0
|
||
# 10.00 * 0.80 = 8.00
|
||
assert limit_down_price(10.0, 0.20, 0.01) == 8.0
|
||
|
||
|
||
# ---- 一字板 / T 字板 ----
|
||
def test_one_word_lock_detected():
|
||
up = limit_up_price(10.0, 0.10, 0.01)
|
||
assert is_one_word_lock(bar(11.0, 11.0, 11.0, 11.0), up) is True
|
||
# 非一字
|
||
assert is_one_word_lock(bar(11.0, 11.5, 10.8, 11.0), up) is False
|
||
assert is_one_word_lock(bar(11.0, 11.0, 10.5, 11.0), up) is False # T 字板非一字
|
||
|
||
|
||
def test_t_lock_detected():
|
||
up = limit_up_price(10.0, 0.10, 0.01)
|
||
# T 字板:开=涨停 收=涨停 low<open
|
||
assert is_t_lock(bar(11.0, 11.0, 10.5, 11.0), up) is True
|
||
# 一字板不是 T 字板
|
||
assert is_t_lock(bar(11.0, 11.0, 11.0, 11.0), up) is False
|
||
# 开≠涨停 不是 T 字板
|
||
assert is_t_lock(bar(10.5, 11.0, 10.5, 11.0), up) is False
|
||
|
||
|
||
# ---- 买单封板拒单(按 symbol 自动判板块)----
|
||
def test_buy_locked_one_word_main_board():
|
||
# 主板 600000,一字涨停 → 买不进
|
||
assert is_locked_for_buy_symbol(
|
||
bar(11.0, 11.0, 11.0, 11.0), "600000", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_buy_locked_t_lock_conservative():
|
||
# T 字板 → 保守拒买
|
||
assert is_locked_for_buy_symbol(
|
||
bar(11.0, 11.0, 10.5, 11.0), "600000", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_buy_not_locked_when_opened():
|
||
# 开板(low 远低于涨停)→ 可买
|
||
assert is_locked_for_buy_symbol(
|
||
bar(10.5, 10.8, 10.2, 10.6), "600000", 10.0, CFG, is_st=False
|
||
) is False
|
||
|
||
|
||
def test_buy_locked_gem_board_20pct():
|
||
# 创业板 300750,10.00 → 涨停 12.00
|
||
assert is_locked_for_buy_symbol(
|
||
bar(12.0, 12.0, 12.0, 12.0), "300750", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_buy_locked_star_board_20pct():
|
||
# 科创板 688981
|
||
assert is_locked_for_buy_symbol(
|
||
bar(12.0, 12.0, 12.0, 12.0), "688981", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_buy_locked_bse_board_30pct():
|
||
# 北交所 830799,5.00 → 涨停 6.5
|
||
assert is_locked_for_buy_symbol(
|
||
bar(6.5, 6.5, 6.5, 6.5), "830799", 5.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_buy_locked_st_5pct():
|
||
# ST 股 5% 涨停,10.00 → 10.50
|
||
assert is_locked_for_buy_symbol(
|
||
bar(10.5, 10.5, 10.5, 10.5), "600000", 10.0, CFG, is_st=True
|
||
) is True
|
||
|
||
|
||
# ---- 卖单封板(跌停对称)----
|
||
def test_sell_locked_one_word_limit_down():
|
||
# 主板一字跌停:10 → 9.0
|
||
assert is_locked_for_sell_symbol(
|
||
bar(9.0, 9.0, 9.0, 9.0), "600000", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_sell_locked_t_lock_limit_down():
|
||
# 跌停 T 字板:开=跌停 收=跌停 high>open(盘中反弹过)
|
||
assert is_locked_for_sell_symbol(
|
||
bar(9.0, 9.5, 9.0, 9.0), "600000", 10.0, CFG, is_st=False
|
||
) is True
|
||
|
||
|
||
def test_sell_not_locked_when_opened():
|
||
# 非跌停形态 → 可卖
|
||
assert is_locked_for_sell_symbol(
|
||
bar(9.5, 9.8, 9.2, 9.6), "600000", 10.0, CFG, is_st=False
|
||
) is False
|