云计算百科
云计算领域专业知识百科平台

用 Python 量化“损失厌恶“:为什么你的止损总是执行不了

用 Python 量化"损失厌恶":为什么你的止损总是执行不了写交易程序的人常有个错觉:策略回测年化30%,实盘就该赚30%。实际往往差很远。差异的一大来源不在策略,在执行者本身的心理偏差。今天不聊策略,聊一个能直接用代码量化的偏差:损失厌恶。## 一、先把概念变成一个可计算的量损失厌恶的标准表述是:同等金额下,损失的效用下降幅度大于收益的效用上升幅度。用价值函数表示(Kahneman & Tversky, 1979):v(x) = x^α , x >= 0v(x) = -λ * (-x)^β , x < 0其中 α、β 约 0.88,λ 就是损失厌恶系数,经验值约 2.25。下面的代码把这条曲线画出来,同时算一个很实用的指标:在给定盈亏比下,需要多高的胜率才能打平。pythonimport numpy as npimport matplotlib.pyplot as pltALPHA = 0.88BETA = 0.88LAM = 2.25 # 损失厌恶系数def value(x): x = np.asarray(x, dtype=float) return np.where(x >= 0, np.power(np.abs(x), ALPHA), -LAM * np.power(np.abs(x), BETA))xs = np.linspace(-100, 100, 401)vs = value(xs)plt.figure(figsize=(7, 5))plt.plot(xs, vs, lw=2)plt.axhline(0, color="gray", lw=0.8)plt.axvline(0, color="gray", lw=0.8)plt.xlabel("盈亏金额")plt.ylabel("主观效用")plt.title("损失厌恶下的价值函数 (lambda=2.25)")plt.grid(alpha=0.3)plt.tight_layout()plt.savefig("loss_aversion.png", dpi=120)跑出来你会看到一个明显的非对称:同样的 100 块,左侧下坠的幅度远大于右侧上升。## 二、由此推出的一个反直觉结论假设盈亏比是 1:1,那么按上面的效用函数,打平所需的胜率是:pythondef breakeven_winrate(loss_aversion, rr=1.0): # 期望效用为0: p*RR^a = (1-p)*LAM a = ALPHA num = loss_aversion den = rr ** a + loss_aversion return num / denfor lam in (1.0, 1.5, 2.25, 3.0): print(f"lambda={lam:<5} 1:1盈亏比需胜率 {breakeven_winrate(lam)*100:.1f}%")输出大致是:lambda=1.0 1:1盈亏比需胜率 50.0%lambda=1.5 1:1盈亏比需胜率 62.0%lambda=2.25 1:1盈亏比需胜率 70.5%lambda=3.0 1:1盈亏比需胜率 75.8%在损失厌恶系数 2.25 的心理状态下,1:1 盈亏比需要 70% 以上的胜率,人才会觉得"这笔交易值"。而真实系统里,1:1 盈亏比的胜率天花板通常在 55% 左右。这就解释了为什么很多人明明用的是正期望系统,却总觉得"这系统不行"——他评判系统用的是主观效用,不是客观期望值。## 三、把它写进回测:模拟一个"会痛"的执行者下面是个最小可跑的例子。同一套信号,两个执行者:一个按规则执行,一个带损失厌恶(亏损时不愿止损、盈利时提前离场)。pythonimport numpy as npdef simulate(prices, stop_loss=0.02, take_profit=0.06, hold_max=20, aversion=0.0, seed=7): rng = np.random.default_rng(seed) equity, trades = 1.0, [] i = 0 while i < len(prices) – hold_max – 1: entry = prices[i] exited = False for j in range(1, hold_max + 1): px = prices[i + j] ret = px / entry – 1 # 带损失厌恶:亏损端止损线被"心理上移",等于拖延 eff_stop = stop_loss * (1 + aversion) # 盈利端目标被"心理下移",等于早跑 eff_tp = take_profit * (1 – 0.4 * aversion) if ret <= -eff_stop or ret >= eff_tp: equity *= (1 + ret) trades.append(ret) i += j exited = True break if not exited: i += 1 return equity, np.array(trades)np.random.seed(0)prices = 100 * np.cumprod(1 + np.random.normal(0.0008, 0.012, 3000))for av in (0.0, 0.5, 1.0, 2.0): eq, tr = simulate(prices, aversion=av) win = (tr > 0).mean() if len(tr) else 0 print(f"aversion={av:<4} 净值={eq:6.3f} 笔数={len(tr):4d} 胜率={win:.1%}")典型输出会显示:随着 aversion 升高,胜率反而上升,但净值下降。这正是损失的来源——不是因为判断错了,而是因为把盈利截短、把亏损拉长,让盈亏比结构性地恶化。## 四、工程上的四条对策1. 止损位入参化,且在开仓时落库止损价不要用"止损比例"在持仓中动态算,应该在开仓那一刻算出绝对价格并写进订单表。改止损需要一次显式的、有记录的操作。2. 规则引擎和执行引擎分离规则引擎跑在无 UI 的进程里,执行器只负责发单。人盯着屏幕的时候,执行器前面最好没有手工干预入口。3. 记录决策依据,不只记录成交订单表加两个字段:signal_id(触发信号)和rule_version(当时用的规则版本)。复盘时能回溯"这是策略赚的,还是我手滑赚的"。4. 用效用而不是盈亏做复盘指标复盘表里同时记两列:pnl(客观)和 plan_adherence(是否按规则执行,布尔值)。长期看,后者和账户曲线的关系更稳定。## 五、小结损失厌恶不是缺陷,是一个可以建模的参数。一旦它变成参数,就不再是不可控的情绪,而是一个可以写进代码、可以被测试、可以被对冲的输入。对做量化的人,真正的门槛从来不在于会不会写策略,而在于能不能把自己的行为也当成一个需要被验证的系统。—合规声明:本文为行为金融学与编程实践的科普分享,仅代表个人观点,不构成任何投资建议。文中代码仅用于原理演示,不构成任何可直接用于实盘的策略。市场有风险,投资需谨慎。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 用 Python 量化“损失厌恶“:为什么你的止损总是执行不了
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!