Pine Script如何基于ATR与账户权益设置自定义开仓仓位
问题原因
策略运行报错和strategy.equity用法无关,核心是三个逻辑错误:
- 仓位计算时机完全倒置:当前代码里的止损距离
differenceLong/differenceShort依赖开仓后才会更新的strategy.position_avg_price、开仓完成后才赋值的atr_at_entry计算。当buy/sell信号触发、strategy.entry准备执行下单的瞬间,账户还没有持仓,上述两个值全为na空值,空仓阶段两个差值还会出现0值,直接触发「除以空值」「除以零」的运行时错误,导致策略崩溃。 - 风险比例未做单位转换:输入参数
risk是百分比单位(比如输入1代表1%风险),直接和权益相乘会把风险金额放大100倍,不符合预设的仓位计算逻辑。 - 仓位值未做合法性校验:Pine Script要求
strategy.entry的qty参数必须为合法正数,传入na、0、负数、非整数值(部分交易品种不支持碎合约)都会触发运行错误。
修复方法
- 先把百分比形式的风险输入转换为小数比例,避免风险金额计算错误。
- 把止损距离的计算提前到开仓信号触发前:信号出现时直接取当前K线的ATR跟踪止损值作为预设止损位,以当根价格为基准计算止损距离,不需要等开仓完成后再从持仓数据里取值。
- 给仓位计算增加兜底逻辑:先判断止损距离大于0再计算仓位,计算完成后做取整、正数校验,过滤非法值。
- 调整
atr_at_entry的赋值逻辑,信号触发当根就记录止损值,方便后续止盈止损计算。
修正后完整代码
//@version=4 //CREDITS to HPotter for the orginal code. The guy trying to sell this as his own is a scammer lol. // Calculate start/end date and time condition startDate = input(timestamp("2022-06-20T00:00:00"), type = input.time) finishDate = input(timestamp("2022-12-01T00:00:00"), type = input.time) time_cond = time >= startDate and time <= finishDate // Inputs src = close keyvalue = input(2.5, title = "Frequência", step = .5) atrperiod = 15 xATR = atr(atrperiod) nLoss = keyvalue * xATR // 百分比风险转小数 risk = input(1, title="Capital Risk (%)") / 100 rr = input(1, title="Risk Reward Ratio", step = 0.5) //Calculate atr metrics xATRTrailingStop = 0.0 xATRTrailingStop := iff(src > nz(xATRTrailingStop[1], 0) and src[1] > nz(xATRTrailingStop[1], 0), max(nz(xATRTrailingStop[1]), src - nLoss), iff(src < nz(xATRTrailingStop[1], 0) and src[1] < nz(xATRTrailingStop[1], 0), min(nz(xATRTrailingStop[1]), src + nLoss), iff(src > nz(xATRTrailingStop[1], 0), src - nLoss, src + nLoss))) pos = 0 pos := iff(src[1] < nz(xATRTrailingStop[1], 0) and src > nz(xATRTrailingStop[1], 0), 1, iff(src[1] > nz(xATRTrailingStop[1], 0) and src < nz(xATRTrailingStop[1], 0), -1, nz(pos[1], 0))) xcolor = pos == -1 ? color.red: pos == 1 ? color.green : color.blue plot(xATRTrailingStop, color = xcolor, title = "Trailing Stop") buy = crossover(src,xATRTrailingStop) sell = crossunder(src,xATRTrailingStop) plotshape(buy, title = "Buy", text = 'Buy', style = shape.labelup, location = location.belowbar, color= color.green,textcolor = color.white, transp = 0, size = size.tiny) plotshape(sell, title = "Sell", text = 'Sell', style = shape.labeldown, color= color.red,textcolor = color.white, transp = 0, size = size.tiny) // 信号触发当根提前记录止损值,计算开仓所需参数 var float atr_at_entry = na // 提前计算当根信号对应的多空止损距离 long_dist = buy ? (src - xATRTrailingStop) : na short_dist = sell ? (xATRTrailingStop - src) : na // 计算合法仓位值,兜底处理非法情况 long_pos = buy and long_dist > 0 ? math.max(1, math.round((strategy.equity * risk) / long_dist)) : na short_pos = sell and short_dist > 0 ? math.max(1, math.round((strategy.equity * risk) / short_dist)) : na // 开仓时记录止损价 if buy and time_cond atr_at_entry := xATRTrailingStop if sell and time_cond atr_at_entry := xATRTrailingStop // 持仓阶段计算止盈价格 longExitPrice = strategy.position_size > 0 ? strategy.position_avg_price + ((strategy.position_avg_price - atr_at_entry) * rr) : na shortExitPrice = strategy.position_size < 0 ? strategy.position_avg_price - ((atr_at_entry - strategy.position_avg_price) * rr) : na // 传入合法仓位值开仓 strategy.entry("long", true, when = buy and time_cond, qty=long_pos) strategy.entry("short", false, when = sell and time_cond, qty=short_pos) if (strategy.position_size > 0) strategy.exit(id="TP", limit = longExitPrice) if (strategy.position_size < 0) strategy.exit(id="TP", limit = shortExitPrice)
补充说明
修正后的代码完全匹配预设仓位计算公式:(账户权益 * 风险比例) / 入场价到ATR止损线的距离,默认加了最小1手的兜底限制,避免计算结果小于交易所最小下单单位。若交易品种支持小数合约,可将math.round替换为math.round_to_mintick,自动适配品种最小报价单位对应的合约精度。
内容的提问来源于stack exchange,提问作者Rayhan Brito
相关产品推荐
相关产品推荐

