You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pine Script实现:基于RSI信号记录ATR水平并触发止损

实现RSI信号触发后的ATR止损逻辑

先理清楚核心逻辑:当RSI发出BUY/SELL信号时,记录当前K线的ATR值并计算对应止损位,后续K线价格触及该止损位时,发出止损信号并平仓。下面分步骤给你具体实现方案:

1. 先搞定ATR的计算

不管你用现成库还是自己写,得先能算出每个K线的ATR值。这里给两种方式:

方式1:用TA-Lib直接调用

如果已经装了TA-Lib,一行代码就能生成ATR列:

import talib
data['atr'] = talib.ATR(data['high'], data['low'], data['close'], timeperiod=14)

方式2:手动实现ATR计算

不想依赖第三方库的话,自己写函数计算真实波幅的移动平均:

def calculate_atr(data, period=14):
    # 计算真实波幅的三个组成部分
    data['high_low'] = data['high'] - data['low']
    data['high_prev_close'] = abs(data['high'] - data['close'].shift(1))
    data['low_prev_close'] = abs(data['low'] - data['close'].shift(1))
    # 取三者最大值作为真实波幅
    data['true_range'] = data[['high_low', 'high_prev_close', 'low_prev_close']].max(axis=1)
    # 计算周期内的移动平均得到ATR
    data['atr'] = data['true_range'].rolling(window=period).mean()
    return data

# 调用函数生成ATR列
data = calculate_atr(data)

2. 记录信号触发时的ATR与止损位

你需要跟踪当前仓位状态(空仓/多头/空头),以及对应的止损价。这里用DataFrame列来存储状态,方便后续处理:

基础实现(循环遍历,适合新手理解)

假设你的数据已经有rsi_signal列,值为BUY/SELL/HOLD:

# 初始化仓位和止损列
data['position'] = 0  # 0=空仓,1=多头,-1=空头
data['stop_loss'] = None

for i in range(1, len(data)):
    prev_pos = data['position'].iloc[i-1]
    current_signal = data['rsi_signal'].iloc[i]
    
    # 触发BUY信号且当前空仓,开多头
    if current_signal == 'BUY' and prev_pos == 0:
        data['position'].iloc[i] = 1
        entry_price = data['close'].iloc[i]
        current_atr = data['atr'].iloc[i]
        # 多头止损:入场价减去当前ATR(可根据策略调整倍数,比如1.5*ATR)
        data['stop_loss'].iloc[i] = entry_price - current_atr
    
    # 触发SELL信号且当前空仓,开空头
    elif current_signal == 'SELL' and prev_pos == 0:
        data['position'].iloc[i] = -1
        entry_price = data['close'].iloc[i]
        current_atr = data['atr'].iloc[i]
        # 空头止损:入场价加上当前ATR
        data['stop_loss'].iloc[i] = entry_price + current_atr
    
    # 未触发新信号,继承上一行的仓位和止损价
    else:
        data['position'].iloc[i] = prev_pos
        data['stop_loss'].iloc[i] = data['stop_loss'].iloc[i-1]
    
    # 检查是否触发止损
    current_pos = data['position'].iloc[i]
    if current_pos == 1:
        # 多头止损:当K线最低价跌破止损位
        if data['low'].iloc[i] <= data['stop_loss'].iloc[i]:
            print(f"止损信号:多头平仓 | 触发价: {data['low'].iloc[i]} | 止损位: {data['stop_loss'].iloc[i]}")
            data['position'].iloc[i] = 0
            data['stop_loss'].iloc[i] = None
    elif current_pos == -1:
        # 空头止损:当K线最高价涨破止损位
        if data['high'].iloc[i] >= data['stop_loss'].iloc[i]:
            print(f"止损信号:空头平仓 | 触发价: {data['high'].iloc[i]} | 止损位: {data['stop_loss'].iloc[i]}")
            data['position'].iloc[i] = 0
            data['stop_loss'].iloc[i] = None

优化实现(向量化操作,适合大数据量)

如果你的K线数据很多,循环效率低,可以用numpy的向量化操作替代:

import numpy as np

# 初始化仓位列
data['position'] = 0

# 标记BUY/SELL信号的触发点(空仓状态下触发)
data['buy_trigger'] = (data['rsi_signal'] == 'BUY') & (data['position'].shift(1) == 0)
data['sell_trigger'] = (data['rsi_signal'] == 'SELL') & (data['position'].shift(1) == 0)

# 填充仓位状态:触发信号时切换仓位,否则继承上一行
data['position'] = data['position'].mask(data['buy_trigger'], 1)
data['position'] = data['position'].mask(data['sell_trigger'], -1)
data['position'] = data['position'].ffill().fillna(0)

# 计算止损价:触发信号时生成,否则继承上一行
data['stop_loss'] = np.where(
    data['buy_trigger'],
    data['close'] - data['atr'],
    np.where(
        data['sell_trigger'],
        data['close'] + data['atr'],
        data['stop_loss'].ffill()
    )
)

# 标记止损触发点
data['stop_loss_trigger'] = np.where(
    (data['position'] == 1) & (data['low'] <= data['stop_loss']),
    'LONG_STOP',
    np.where(
        (data['position'] == -1) & (data['high'] >= data['stop_loss']),
        'SHORT_STOP',
        None
    )
)

# 触发止损后重置仓位和止损价
data['position'] = np.where(data['stop_loss_trigger'].notna(), 0, data['position'])
data['stop_loss'] = np.where(data['stop_loss_trigger'].notna(), None, data['stop_loss'])

# 打印止损信号
for idx, row in data[data['stop_loss_trigger'].notna()].iterrows():
    print(f"止损信号:{row['stop_loss_trigger']} | 触发价: {row['low'] if row['stop_loss_trigger'] == 'LONG_STOP' else row['high']} | 止损位: {row['stop_loss']}")

3. 关键注意事项

  • 止损倍数调整:示例中用的是1倍ATR,你可以根据策略改成1.2/1.5倍,更符合风险偏好
  • 入场价选择:示例用的是信号触发K线的收盘价,你也可以用开盘价或者实时成交价格,根据你的信号执行逻辑调整
  • 移动止损:如果需要随着行情更新止损位(比如跟踪ATR变化),可以在持有仓位时定期重新计算止损价,而不是只记录信号触发时的ATR
  • 信号优先级:要确保止损信号的优先级高于新的RSI信号,避免触发止损后立刻开新仓

内容的提问来源于stack exchange,提问作者Ovgu Sayan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 09:45:35