跳转至

支撑压力位与风险预算策略

sr_risk_budget 是一个固定参数、只做多的沪深主板日线研究策略,入口为 examples/25_sr_risk_budget.py。它复用已有支撑压力研究模块中的 ATR 和历史区间计算,但独立管理订单和逐日风险,不覆盖原来的 ashare_sr_leader 策略。

本策略尚未证明持续盈利。 风险参数是计划约束,不是收益承诺或实际亏损上限;测试通过只证明被测试的代码行为。

买卖规则

  1. 沪深 300 收盘价高于 120 日均线,且均线高于 20 个交易日前,才允许新开仓。条件不满足或指数数据缺失时,提交清仓请求。
  2. 个股站上不下降的 60 日均线,收阳且收盘高于上一日;过去 20 日估算日均成交额至少 5000 万元,ATR/股价不超过 6%。成交额估算使用 close × volume,成交量单位必须为股。
  3. 两种入场:回踩前 60 日最低价形成的支撑并收回;或在此前 5 日出现放量突破,随后回踩突破前冻结的 60 日压力位。压力位由突破前的数据确定,不使用未来拐点。
  4. 初始止损取“支撑减 0.5 ATR”和“买入限价减 1.5 ATR”中较低者;计划止损距离必须在 1.5%—8% 之间。
  5. 支撑反弹以原压力位下方 0.3 ATR 为目标。突破回踩参考突破前的历史上方压力;没有上方压力时,使用明确标为推算值的 3R 目标。预期盈亏比小于 1.8 的交易放弃。
  6. 止损只会上移:持仓最高收盘价减 3 ATR。收盘触及止损、达到目标或持仓满 40 个交易日时提交卖出请求。卖出后等待 5 个交易日再考虑同一股票。

仓位与组合保护

参数 默认值 含义
risk_per_trade 0.5% 单笔计划风险,按止损距离并预留费用估算
max_open_risk 2% 新开仓时,已有风险与待成交买单合计预算
max_stock_weight 15% 单只股票新开仓金额上限
max_exposure 60% 新开仓时的组合股票市值上限
max_positions 5 最大持仓数量
volume_participation 0.5% 买单不超过过去 20 日日均成交股数的该比例
halt_drawdown 10% 从本次风控周期净值高点回撤达到阈值,提交全部退出请求
halt_days 20 熔断后至少等待 20 个交易日,且已空仓、大盘过滤恢复才重新交易

下单股数取风险、现金、个股仓位、组合仓位和历史流动性五项约束的最小值,再向下取整到 100 股。最低佣金纳入现金和风险预留。待卖仓位在真正成交前继续占用资金与风险,存在退出订单时不新开仓。

市价波动会使实际权重突破计划权重;本策略不为维持固定比例而每日机械调仓。熔断恢复时重置的是下一次风险周期的高点,不会重置报告中的累计净值和最大回撤。

信号与成交时序

只使用日线 after_trading_end 回调。在 15:00 后,将 attribute_history 返回的昨日及更早历史,与 data[code] 的当日已完成 K 线合并。不能把这个回调挪到早盘。

  • T 日收盘形成信号;最早在 T+1 日开盘撮合。
  • 买入采用不高于信号收盘价约 0.5% 的限价,撮合后的滑点价格也必须满足限价。
  • 买单仅尝试下一次开盘;当天收盘取消未成交余量。部分成交只管理真实持仓。
  • 止损和止盈是收盘信号,不是盘中保证成交的止损单。买入当日不能卖出;跌停、停牌和跳空可能让实际亏损明显超过预算。
  • 被引擎取消的卖单,只要退出意图未完成,就在下一次收盘重新提交;部分成交卖单保留剩余数量。

运行与输入数据

在仓库根目录执行:

pip install -e ".[dev]"
python examples/25_sr_risk_budget.py --download --start 2021-01-01 --end 2025-12-31
python examples/25_sr_risk_budget.py --stress --start 2021-01-01 --end 2025-12-31

--download 会下载并覆盖 data/sr_risk_budget/ 中的快照。重复评估时不加此选项,可以保持输入不变。默认股票池直接采用 examples/_defaults.py 的 8 只股票,属于自选观察名单,并非历史时点的指数成分。

也可以提供 CSV:

python examples/25_sr_risk_budget.py --data-dir /path/to/snapshots --stress

文件名为 <code>_daily_qfq.csv,包括 000300.XSHG_daily_qfq.csv。首列为日期索引,至少包含 open,high,low,close,volume,价格为同一口径的前复权人民币价格,股票成交量为股。--download 将 eqlib 主板股票接口的成交量从手乘以 100 转为股;已提供的 CSV 不会再转换。指数成交量保留源单位,不参与策略的流动性计算。文件必须覆盖测试末日,并在开始日前提供至少 config.history_bars 根有效日线(默认 140 根)。重复、乱序、非有限数值、错误 OHLC、基准缺交易日或时间覆盖不足都会报错,不会悄悄缩短测试区间。股票缺失交易日会记录在清单中,不会凭空补成交。

离线运行使用打包交易日历,并把引擎和报告的读取绑定到同一份 CSV,避免回测结束时又下载另一版指数数据。这一示例适配器作用于当前 Python 进程;不要在同一个进程中并发运行它。

默认使用统一佣金 0.025%、每笔最低 5 元,卖出印花税由引擎按日期处理;基础滑点为单边 0.1%。--stress 再跑一次双倍佣金及最低佣金、单边 0.3% 滑点。税率减半生效日期可查税务总局公告。

输出目录 reports/sr_risk_budget/:

文件 用途
summary.json 固定参数、成本、各输入文件 SHA-256、完整区间及逐年指标、费用压力测试
equity.csv 每日净值、现金、持仓比例、熔断状态
trades.csv 引擎实际成交及费用
events.csv 买入限价、支撑、止损、目标、退出原因、熔断与恢复事件

逐年指标来自同一条连续持仓路径,使用前一个观察点的净值计算边界收益;不把每年重置成现金,也不把这些切片称为独立样本外测试。该示例单次运行不做参数搜索。不得挑出表现最好的年份宣称稳定盈利。

仅在验证合成行情时使用 --synthetic,报告会标记为执行测试,不作为真实收益证据。

在其他策略中使用

from eqlib import run_backtest
from eqlib.strategies import SRRiskConfig, make_sr_risk_budget_strategy

initialize = make_sr_risk_budget_strategy(
    ["601398", "601318", "600276", "601088"],
    config=SRRiskConfig(),
)
result = run_backtest(initialize, "2023-01-01", "2025-12-31", starting_cash=1_000_000)

可传入 eligible(code, date),使用当时已知的股票池成员与 ST 状态过滤,并在标的失去资格后提交退出请求。不传时明确使用静态股票池;不能把今天的名称或今日 ST 状态当成历史事实。API 为 EXPERIMENTAL,仅支持主板日线研究,未提供实盘券商适配。

验证边界

回归测试覆盖支撑反弹、突破回踩、未来行情变动不影响历史信号、费用与整手限制、同步资金占用、隔日撮合、部分成交、跳空穿越止损、跌停卖出重试、熔断恢复及 CSV 截断。合成行情只用于验证这些行为,不作为收益证据。

当前版本仍继承引擎的研究近似:前复权价格参与撮合、按日成交量限制撮合规模、估算板块涨跌停,没有完整的历史 ST/退市清单、真实开盘集合竞价队列或公司行为现金与股数账本。因此,既不能保证“稳定赚钱”,也不能仅靠此回测把策略认定为可实盘。

在收益判断前,应冻结参数和历史时点股票池,在未参与设计的新数据上记录净收益、回撤、完整交易数量、不同市况及成本压力表现,再进行模拟盘。任何门槛不通过都应保留失败结果。

交易约束核对来源:上交所现行交易规则、上交所整手及零股申报说明、港交所互联互通 FAQ。

可选突破规则与 2026 年 9 月研究记录

SRRiskConfig() 保留原行为。新增三个严格布尔参数:

参数 默认值 行为
allow_breakout False 支撑反弹和回踩均未触发时,允许直接突破此前 level_window 日最高价
require_market_slope True 设为 False 只取消大盘均线斜率要求,仍须收盘高于均线
exit_on_market_filter True 设为 False 不因大盘过滤失效直接清仓;新开仓过滤、个股止损、持仓期限、资格退出和组合熔断继续生效

直接突破使用不包含信号日的历史最高价,收盘须超过该价格 0.1 ATR,且不超过 1.5 ATR,成交量至少达到此前 20 日均量。它沿用原有止损、盈亏比、费用预留和次日限价撮合;上方历史压力只使用信号日前已知数据,没有历史压力时的 3R 目标是推算值。默认不启用,因为下面的验证未通过。

python examples/25_sr_risk_budget.py --allow-breakout --stress \
  --start 2020-01-01 --end 2026-09-10 \
  --data-dir /path/to/frozen-inputs --output reports/sr_breakout

原策略在同一份固定 8 股历史上的平均仓位仅 2.34%,完成 26 轮交易,其中 6 轮盈利。接近此前 60 日最低价、同时站上不下降的 60 日均线等条件叠加后,整个区间没有支撑反弹信号,剩下 38 个突破回踩候选。这解释了低交易频率和资金闲置;增加信号本身不保证提高胜率。

本轮先声明候选再运行,进行了三轮、共 11 个配置(含原策略)。开发期为 2020—2022,验证期为 2023—2024;每段以 100 万元独立开始,用之前的日线预热。后两轮利用过验证结果,因此存在重复选择偏差。全部结果如下:

候选 开发期净收益 验证期净收益 验证期最大回撤
baseline -0.76% -1.30% 1.78%
short_levels +1.32% -1.30% 2.10%
breakout +7.34% -0.78% 2.19%
trend_exit +0.84% -0.30% 1.80%
early_market +7.27% -5.19% 6.04%
long_trend +6.84% -4.90% 5.98%
early_trend_exit +0.28% -1.56% 2.74%
channel60 +7.97% -0.49% 1.44%
stock_exits +8.17% -1.05% 3.28%
channel60_stock_exits +8.80% -1.46% 3.21%
patient_exits +8.02% -0.67% 2.19%

原定门槛为两段净收益均大于零、最大回撤均小于 12%、成交数多于原策略,再检查加倍佣金及 0.3% 滑点。没有配置通过收益门槛,没有可晋级策略。 channel60 仅作为改动最少的后续比较候选,在查看后段前冻结;它等于 SRRiskConfig(allow_breakout=True)。没有因完整区间上涨而修改门槛。

检查 原策略 channel60
2020-01-02—2026-09-10 连续净收益 -0.11% +5.07%
同期年化收益(244 个交易日/年) -0.02% +0.75%
同期最大回撤 3.96% 3.72%
同期实际成交 / 完成轮次 52 / 26 98 / 49
同期平均仓位 2.34% 3.66%
2025-01-02—2026-09-10 独立后段净收益 +2.37% -2.39%
候选完整区间费用压力净收益 — +4.09%

同期沪深 300 价格指数收益 +11.03%。候选完整区间年化夏普为 -1.04(扣除 3% 年无风险基准;现金不计息)。候选验证期费用压力净收益 -0.70%,后段费用压力 -2.45%,仍不通过。完整区间有改善,但后段变差,收益主要来自早期行情;默认配置保持原样,两个版本都没有建立持续盈利证据。

此前已经看过原策略的完整历史,因此后段检查不是经认证的全新样本外数据。独立重置的分段收益不能简单相乘还原连续持仓路径。费用压力会改变限价成交和数量,因此交易路径可能不同。

数据口径和复现

所有候选共享同一份 2019-01-02—2026-09-10 快照,股票池、风险预算和佣金一致,没有按赢家换股票。中国神华有 2025-08-04—2025-08-15 的 10 个停牌交易日,未补造成交;可核对公司复牌公告。

这次历史包不是原生腾讯前复权:原生神华前复权在部分早期日期出现非正数,因而全部八股统一采用腾讯后复权乘以终点参考价格的固定比例,文件名仅为兼容保留 _daily_qfq.csv。成交量为股。公式为 input_OHLC[t] = hfq_OHLC[t] × qfq_close[2026-09-10] / hfq_close[2026-09-10]。终点归一化会影响绝对价格过滤和整手买入;缺少未复权成交价格、除权除息现金/股数账本、历史 ST 和时点成分,不能把结果当成可投资净收益。基准为价格指数,也没有统一分红再投资账本。

仓库 research/sr_risk_budget_2026_09/results.json 保存声明时间、所有参数、失败门槛、分段和逐年指标、输入 SHA-256。行情 CSV 不随代码发布;复现数字需要原归档快照,新下载或不同归一化数据属于不同实验。

python scripts/research_sr_risk_budget.py --candidate channel60 --period full \
  --data-dir /path/to/frozen-inputs --output reports/replay
python scripts/research_sr_risk_budget.py --candidate channel60 --period full --stress \
  --data-dir /path/to/frozen-inputs --output reports/replay

--candidate 可选表中 11 个名字;--period 可选 development、validation、later_check、full。每次只运行一个配置和区间,不自动寻找最优参数,不覆盖已有结果。辅助在线指数图省略,基准指标仍从本地快照计算。脚本保存实际成交、净值、事件、参数、费用及源文件摘要。

下一步应优先补齐时点股票池和原始价格/公司行为数据,再预先声明新的信号假设与标准,用未参与设计的数据或模拟盘检验。继续在已看过的年份调参不会产生新的独立证据。大量尝试会放大选择偏差,参见 Bailey 等关于回测过拟合的研究。本轮没有计算 PBO 或声称统计显著性。