【Python量化实战宝典 #26】止损与回撤控制手册:移动止损、最大回撤(Python 可跑)
手册定位:模块四第 2 篇。仓位定好后,怎么锁住下行 决定长期能否活下来。本篇讲移动止损、固定止损、组合最大回撤约束三种方法。
数据来源复用 #02 历史K线(价格序列)+ #24 净值曲线。
1. 你将得到什么
- 移动止损 (回撤阈值自动下移止盈)、固定止损 (单笔 -X%)、组合最大回撤熔断三种代码;
- 止损对净值曲线的保护效果对比;
- 实盘落地的滑点/流动性约束;
- 止损的 4 个坑(止损过紧、移动止损滞后、熔断后踏空、不考虑滑点)。
2. 取数约定(复用)
| 用途 | 来源 | 见 |
|---|---|---|
| 价格序列 | /hs/history/{代码}.{市场}/d/n |
#02 |
| 净值曲线 | #24 绩效 | #24 |
3. 数据来源(复用,不重复罗列)
详见 #02 历史K线接口手册(日线端点);净值见 #24。
4. 核心模板函数(自包含可跑)
python
import pandas as pd
import numpy as np
_MOCK = True
def trailing_stop(price, pct=0.1):
"""回撤超过 pct 则触发止损(返回持仓 1/0)。"""
s = pd.Series(price)
peak = s.cummax()
draw = s / peak - 1
return (draw > -pct).astype(int)
def fixed_stop(pnl, pct=0.05):
"""单笔浮亏超过 pct 止损(返回持仓 1/0)。"""
s = pd.Series(pnl)
return (s > -pct).astype(int)
def drawdown_breaker(equity, limit=0.20):
"""组合净值回撤触及 limit 则清仓(返回持仓 1/0)。"""
s = pd.Series(equity)
dd = s / s.cummax() - 1
return (dd > -limit).astype(int)
def run_check():
price = [10, 10.5, 11.0, 10.8, 10.0, 9.5, 9.8, 10.2] # 中段回撤
stop = trailing_stop(price, pct=0.08)
equity = [1.0, 1.05, 1.10, 1.08, 1.00, 0.92, 0.95, 1.02]
brk = drawdown_breaker(equity, limit=0.15)
assert stop.iloc[-1] in (0, 1) and brk.iloc[-1] in (0, 1)
assert brk.iloc[5] == 0 # 第6日回撤-8%>15%? 实际-8% 不触发;改测极限
# 重新验证极端: 回撤>limit 才触发
eq2 = [1.0, 1.1, 0.8]
assert drawdown_breaker(eq2, limit=0.15).iloc[2] == 0
print("校验通过 | 移动止损末态=%d 熔断末态=%d" % (stop.iloc[-1], brk.iloc[-1]))
return stop, brk
if __name__ == "__main__":
run_check()
5. 跑通示例
python
stop, brk = run_check()
print("当前:", "持仓" if stop.iloc[-1] else "已移动止损", " 组合:", "正常" if brk.iloc[-1] else "已熔断清仓")
6. 坑与注意事项
- 止损过紧:日线 5% 止损遇上正常波动会被反复洗出,止损幅度要匹配策略周期。
- 移动止损滞后:移动止损在价格回撤后才触发,急跌时已经跌了一段,要接受「让利润奔跑」的代价。
- 熔断后踏空:最大回撤熔断清仓后若反弹会踏空,可设「回撤修复后再入场」条件。
- 不考虑滑点:止损单在极端行情可能以更差价成交,回测要留滑点缓冲。
7. 小结与下一篇预告
止损/回撤控制把下行锁住。下一篇讲可转债双低策略------用 #08 的双低值构建转债组合。
下一篇预告:《【Python量化实战宝典 #27】可转债双低策略手册:价格+溢价双低组合(Python 可跑)》
8. 免责声明
本文为止损方法示例,演示数据为虚构,不构成投资建议。