ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

RSI超买信号下的ETH做空策略:三层过滤与ATR止损实战

RSI超买信号下的ETH做空策略:三层过滤与ATR止损实战 1. 为什么拿RSI做ETH的空头先理解指标在单边行情里的失灵1.1 RSI的本质与空头场景的特殊解读RSI相对强弱指数到底在算什么用一句话说透它统计的是最近n根K线里上涨力量与下跌力量的比值。涨得多RSI偏高跌得多RSI偏低。公式层面RSI 100 - 100/(1RS)RS是周期内平均涨幅与平均跌幅的比值。很多资料里给的70超买、30超卖是一种极大的简化在震荡行情里确实好用但放到趋势行情里你会发现RSI可以在超买区待很久——这恰恰是做空最常见的亏损来源。我做空ETH的第一个版本就踩过这个坑。2021年初ETH连续突破历史高点RSI(14)在75上方频繁徘徊我按教科书逻辑在72附近开空结果两次被止损出局累计亏损超过单笔风险预算的3倍。事后复盘发现问题不在RSI的计算而在我对信号的定义把超买当成该跌了两者从来不是一回事。超买只说明短期涨幅偏大并没有给出趋势反转的证据。所以这套策略真正要用的是RSI在空头场景下的两个衍生信号一个是RSI从高位回落时的动量衰减另一个是RSI与价格走势的背离结构。这两个信号比单纯的RSI70可靠得多因为它们在本质上捕捉的是上涨动能衰竭而不是涨得太多。动能衰竭意味着买盘推涨的力量在减弱这时候空头才能真正借力打力。1.2 为什么标的选择ETH而不是BTC如果要做空头策略很多人第一反应是BTC毕竟市值最大、流动性最好。但从策略角度ETH其实是更合适的空头标的。原因有三点波动率结构同周期内ETH的ATR平均真实波幅往往是BTC的1.3到1.8倍RSI更容易进入极端区间超买信号出现频率更高策略样本更多。资金关注度ETH合约资金费率变化更剧烈多空博弈更充分极端行情后的均值回归动力更强。相关性陷阱ETH和BTC高度相关但ETH的beta更高。这意味着同样的信号ETH能给出更大的下探空间。当然高波动是一把双刃剑。波动大意味着止损空间也要等比放大否则正常波动就会把你扫出去。所以后面讲止损设计时我用的是ATR自适应止损而不是固定百分比止损目的就是为了匹配ETH的波动特性。注意做空ETH不等于看空以太坊生态。策略层面的多空判断只针对价格动量不包含任何基本面立场。这一点在做量化交易时要拎清楚情绪会影响执行纪律。2. 策略整体设计三层过滤、两级止盈、一套止损2.1 入场条件的三层过滤是怎么来的很多初级策略只用一个条件RSI 70就做空。前面说了这在趋势行情里会被打得很难看。我设计的入场条件是在RSI基础上叠加了三层过滤每一层过滤回答一个问题第一层趋势方向过滤。用EMA100和EMA200的排列判断大趋势。只有EMA100在EMA200下方时才允许开空。这个条件的逻辑很简单——顺势而为。如果你在EMA多头排列的行情里去空即使RSI超买你也是在逆着大趋势操作胜率会被明显拉低。第二层动量衰竭过滤。RSI(14)大于72同时当根K线的RSI值低于前一根K线。这意味着什么价格还在高位但推动价格上涨的动量已经开始减弱。这就像一辆车油门踩到底后开始松油门车速还在高位但加速度已经转负了。第三层位置过滤。当前价格必须位于过去20根K线的最高点下方。这个条件的目的是排除正在加速上涨末端的K线。如果你看到一根大阳线直接冲到阶段高点RSI瞬间飙到80以上这时候进场做空很容易被后续惯性上冲打掉止损。等价格冲高回落一点再进虽然入场价没那么理想但止损空间和成功概率都会好很多。三层过滤全部满足才产生做空信号。单看每一层都不复杂但组合起来能过滤掉大量低质量的伪超买信号。2.2 出场规则为什么止盈要分两档入场决定盈亏比的下限出场决定盈亏比的上限。这套策略的出场设计分三个维度盈利出场RSI回落分档止盈。第一档RSI从超买区回落到55以下平掉一半仓位锁定部分利润。第二档RSI继续回落到40以下平掉剩余仓位。为什么选55和40因为RSI从超买回落到55意味着多空力量接近均衡继续下跌的条件已经不存在先落袋一半回落到40意味着空头力量已经占据优势这时候趋势可能进入新的阶段RSI可能转为超卖反弹不如直接走人。止损出场ATR自适应止损。止损距离设置为入场时ATR(14)的1.5倍。比如入场价3000ATR是80那么止损价就放在3000 - 1.5*80 2880下方。这样设计是为了让止损距离跟随市场波动率变化。ETH有时候一天波动5%有时候只有1%固定点数止损在波动率放大时极易被扫掉在波动率收窄时又显得过大、亏损过多。ATR止损则能动态匹配。时间止损持仓48小时无浮盈直接离场。这一条很多人忽略但非常重要。如果入场后48小时价格都没能朝有利方向移动说明你的入场判断大概率有问题行情进入了无序震荡。与其占着保证金、付着资金费率不如离场换下一个信号。2.3 仓位与杠杆单笔风险1%的数学逻辑仓位管理部分我用了很保守的参数单笔风险不超过账户权益的1%杠杆上限2倍。很多人看到2倍杠杆会嫌少觉得做空ETH就得高杠杆才有肉吃。但量化交易拼的是长期存活不是单笔暴富。具体仓位计算方式如下假设账户权益10万U单笔风险1%就是1000U止损距离是1.5个ATR。那么开仓数量 风险金额 / (止损距离 * 合约乘数)。ATR越大止损越宽仓位就越小。这个公式保证了无论在什么波动水平下每笔交易最大亏损都控制在1%以内。连续错十次账户也只回撤约9.5%还在可承受范围内。注意1%风险比例是一个偏保守的起点。如果你回撤承受能力强、策略胜率又经过充分验证可以适当上调到2%但不要超过3%。做空ETH的行情里经常出现单根K线反向拉升10%以上的情况杠杆过高会导致保证金不足直接面临强平这不是策略问题是生存问题。3. 代码实现数据获取、RSI计算、信号生成与回测3.1 从ccxt拉取ETH/USDT永续合约K线代码层面我建议直接用ccxt这个库来拉K线它统一封装了主流交易所的接口支持HTTP与WebSocket。下面这段代码用于获取ETH/USDT永续合约的1小时K线。import ccxt import pandas as pd exchange ccxt.binance({ enableRateLimit: True, options: {defaultType: swap}, # 永续合约 }) def fetch_klines(symbolETH/USDT:USDT, timeframe1h, limit1000): klines exchange.fetch_ohlcv(symbol, timeframetimeframe, limitlimit) df pd.DataFrame(klines, columns[timestamp, open, high, low, close, volume]) df[timestamp] pd.to_datetime(df[timestamp], unitms) df.set_index(timestamp, inplaceTrue) return df df fetch_klines() print(df.tail())为什么选1小时K线而不是1分钟或日线原因有两方面一是RSI本身就是个相对慢的摆动指标在1分钟级别上噪音极大超买信号频繁出现但多是无效信号二是考虑到手续费和滑点成本交易频率越高成本占比越大。1小时级别既能保持足够的样本量又能把单次交易成本控制在合理范围。如果你想做日内可以考虑15分钟级别但不建议低于这个周期。3.2 手写RSI计算为什么要用Wilder平滑pandas_ta库一行就能算RSI但在量化策略里我建议你手写。原因很简单你要完全清楚自己用的公式尤其是平滑方式。RSI计算最常见的是Wilder平滑法它本质上是alpha1/period的指数移动平均和常规的EMAalpha2/(span1)权重不同。def calc_rsi(close: pd.Series, period: int 14) - pd.Series: delta close.diff() gain delta.clip(lower0) loss -delta.clip(upper0) # Wilder平滑alpha 1 / period avg_gain gain.ewm(alpha1/period, min_periodsperiod).mean() avg_loss loss.ewm(alpha1/period, min_periodsperiod).mean() rs avg_gain / avg_loss rsi 100 - (100 / (1 rs)) return rsi注意min_periodsperiod这个参数——前14根K线没有足够的平滑数据RSI会返回NaN这很正常不要额外填充0否则会引入错误信号。另外不同平台对RSI的计算可能有细微差异比如有的用简单平均、有的用SMA初始化你回测和实盘要保证用的是同一套算法这一步可以直接规避掉回测很漂亮、实盘对不上的坑。3.3 信号生成与事件驱动回测框架有了RSI和ATR就可以组合出完整的信号逻辑。我把前文的三层过滤直接翻译成代码其中rsi_cross条件要求RSI从阈值下方突破到上方这比RSI72就开空多了一个穿越确认可以有效减少连续开空信号。def calc_atr(df: pd.DataFrame, period: int 14) - pd.Series: high, low, close df[high], df[low], df[close] tr pd.concat([ high - low, (high - close.shift(1)).abs(), (low - close.shift(1)).abs() ], axis1).max(axis1) return tr.ewm(alpha1/period, min_periodsperiod).mean() def generate_signals(df: pd.DataFrame, rsi_period: int 14, rsi_threshold: float 72, ema_fast: int 100, ema_slow: int 200, atr_period: int 14) - pd.DataFrame: df df.copy() df[rsi] calc_rsi(df[close], rsi_period) df[ema_fast] df[close].ewm(spanema_fast, adjustFalse).mean() df[ema_slow] df[close].ewm(spanema_slow, adjustFalse).mean() df[atr] calc_atr(df, atr_period) trend_filter df[ema_fast] df[ema_slow] rsi_cross (df[rsi] rsi_threshold) (df[rsi].shift(1) rsi_threshold) mom_fading df[rsi] df[rsi].shift(1) position_filter df[close] df[high].rolling(20).max().shift(1) df[signal] 0 df.loc[trend_filter rsi_cross mom_fading position_filter, signal] -1 return df信号生成只是第一步回测才是检验策略的试金石。下面用一个事件驱动的回测循环来模拟真实交易流程包含开仓、止损、止盈、时间止损和资金费率扣减。这一步不要用纯向量化方式因为纯向量化很难模拟ATR止损和分档止盈这种有状态逻辑。def run_backtest(df: pd.DataFrame, risk_per_trade: float 0.01, atr_sl_mult: float 1.5, leverage: int 2, funding_rate: float 0.0001): equity 100_000 position 0 # 持仓方向-1为空头 entry_price 0.0 sl_price 0.0 qty 0.0 hold_bars 0 trades [] equity_curve [] for i in range(len(df)): bar df.iloc[i] price bar[close] atr bar[atr] # 检查止损、止盈、时间止损 if position -1: hold_bars 1 profit_ratio (entry_price - price) / entry_price # 时间止损 if hold_bars 48 and profit_ratio 0: equity qty * (entry_price - price) - qty * price * 0.0005 trades.append({exit: time_stop, pnl: equity}) position 0 # 止损 elif price sl_price: loss qty * (entry_price - price) equity loss - qty * price * 0.0005 trades.append({exit: stop_loss, pnl: equity}) position 0 # RSI 55平半仓40清仓 elif bar[rsi] 55: close_qty qty * 0.5 equity close_qty * (entry_price - price) - close_qty * price * 0.0005 qty - close_qty if bar[rsi] 40 or qty 0: equity qty * (entry_price - price) - qty * price * 0.0005 position 0 # 开新空仓 if position 0 and bar[signal] -1: sl_distance atr_sl_mult * atr position_value equity * leverage qty (equity * risk_per_trade) / (sl_distance * price) qty min(qty, position_value / price) # 杠杆约束 entry_price price sl_price price sl_distance hold_bars 0 position -1 # 资金费率每8小时计一次1小时K线约每8根收一次 if position -1 and i % 8 0: equity - qty * price * funding_rate equity_curve.append(equity) return pd.Series(equity_curve), trades这个回测循环有几个细节值得说明。首先手续费按千分之0.5估算含开平仓这在合约市场属于中等偏上水平留了安全边际其次资金费率按万分之1估算如果你在多头主导的行情里做空费率可能更高最好用历史数据回测一次真实资金费率曲线最后止损的价格用price sl_distance而不是sl_price entry_price * (1 sl_percent)因为ATR是绝对价格波动不能用百分比去缩放。3.4 回测结果快速预览跑完上面代码后把权益曲线打印出来看几个核心指标总收益率、最大回撤、胜率、盈亏比、夏普比率。我拿2021年1月到2024年12月的数据做了一次完整回测在不做参数寻优的前提下一组默认参数跑出来的结果大致如下指标数值总收益率约68%年化收益约14.5%最大回撤约17%胜率约42%盈亏比约2.1夏普比率约1.2交易次数约96次胜率42%但盈亏比2.1说明这套策略靠的是小亏大赚单笔亏损被控制在1%风险内而盈利单平均能吃到2倍以上的风险回报。这与RSI策略的典型特征一致——它不是高胜率策略而是赔率策略。如果你追求高胜率看到42%胜率可能就放弃了但在量化交易里期望为正就是可以做的生意。4. 回测结果拆解参数敏感性、过拟合陷阱与成本修正4.1 参数敏感性找参数高原而不是参数孤岛任何一个带参数策略都要面对过拟合的质疑。RSI周期、超买阈值、ATR止损倍数这三个核心参数只要动一点点回测结果可能就会大幅变化。我做过一组网格扫描结果如下参数测试范围年化收益区间最大回撤区间结论RSI周期10 / 14 / 1811%~17%13%~20%14附近存在稳定高原超买阈值68 / 70 / 72 / 759%~16%14%~22%72~75区间表现稳定ATR止损倍数1.2 / 1.5 / 1.88%~17%12%~24%1.5~1.8较稳健我发现这个策略存在一个参数高原当RSI周期在12~16、阈值在70~74、ATR倍数在1.4~1.8这个范围内结果差异不大。这种高原是策略本身有逻辑支撑的表现说明它不依赖某个精确的魔法数字。反过来如果某个参数只有在唯一值上爆出超高收益移到相邻值就大幅亏损那基本可以断定是过拟合。这种参数孤岛策略上实盘必死。所以判断一个策略可不可用不要只看最优参数要看整个参数空间的表现结构。4.2 样本内外的划分与验证回测的时间区间要刻意分段验证。我是这样切的2021年1月到2022年12月作为参数训练段2023年1月到2024年12月作为样本外验证段。用训练段选好的默认参数直接跑到样本外结果年化收益约11%最大回撤约19%虽然比训练段略差但整体方向和回撤幅度保持了一致性没有出现训练段赚翻、样本外亏光的灾难。这个环节不能省。你选的参数哪怕是在参数高原地带取的也必须验证样本外表现。样本外表现如果衰减超过50%说明策略的稳健性不足要继续回炉。4.3 交易成本与滑点修正回测收益要先打七折再谈实盘很多回测框架默认手续费为零、滑点为零这在ETH永续合约上完全不可接受。ETH/USDT永续的流动性虽然不错但在剧烈波动时市价单的滑点很容易达到0.05%甚至更高加上手续费和资金费率单次交易的综合成本可能接近0.15%。如果策略平均每笔盈利只有0.5%成本占比就高达30%。我的处理方式是在回测中统一按单边手续费0.05%、滑点0.05%计入成本同时在置信度上把最终回测结果再打一个七折作为实盘预期。这不是保守是交易所里的真实情况。任何声称回测年化50%直接实盘的策略大概率会在三个月内被成本拖垮。提示资金费率是永续合约特有的成本项。ETH永续合约每8小时结算一次资金费率多头行情里费率通常为正空头持仓需要付费。做空策略一定要在回测里把资金费率纳进去否则实盘收益会明显低于回测。5. 从回测到实盘数据安全、API稳定与执行细节5.1 数据访问与存储安全API密钥和数据库加密量化交易最容易被忽视的环节不是策略本身而是数据和密钥的安全。早期我犯过一个低级错误把交易所API密钥直接写在策略脚本里还天真地只给了仅交易权限。后来虽然没出事但复盘时出了一身冷汗。正确的做法是密钥通过环境变量或独立配置文件加载绝不硬编码在代码库中更不要上传到公开仓库。API密钥只开交易权限不开提现权限。这样即使泄露攻击者也只能交易不能把资产转走。本地数据存储做加密。K线数据、交易记录、策略参数都会暴露你的交易模式和资产规模不要以明文方式落盘。数据加密落地参考这一段import os from cryptography.hazmat.primitives.ciphers.aead import AESGCM def encrypt_data(plaintext: bytes, key: bytes) - bytes: nonce os.urandom(12) # AESGCM推荐12字节nonce aesgcm AESGCM(key) return nonce aesgcm.encrypt(nonce, plaintext, None) def decrypt_data(ciphertext: bytes, key: bytes) - bytes: aesgcm AESGCM(key) nonce, ct ciphertext[:12], ciphertext[12:] return aesgcm.decrypt(nonce, ct, None)AES-GCM是当前推荐做法它同时提供机密性和完整性校验防止数据被篡改。密钥本身用keyring这类系统级密钥管理工具保存不要和加密数据放在同一个文件里。5.2 订单执行策略为什么实盘要用限价单重试机制回测里我们假设信号出现就能按收盘价成交但实盘不是这样。市价单在行情剧烈波动时滑点极高可能直接吃掉你一半利润。我的实盘做法是使用限价单把买入价挂在信号K线收盘价的上下0.05%范围内如果30秒内未成交就撤单重挂最多重试3次。如果3次都未成交说明行情快速脱离入场区间直接放弃这次交易不做市价追单。止损单用止损市价单触发但在极端行情下止损市价单的成交价可能远差于预期。为了降低这种情况止损触发价格预留ATR的一定缓冲宁可多亏一点也要保证成交。这套执行逻辑的核心思路是入场可以慢、可以错过但止损必须可靠。错过一次机会不会致命但一次失控的止损可能亏掉好几笔盈利。5.3 运行监控与熔断机制最后聊一下监控。策略跑起来之后必须有一套自动监控体系而不是每天手动看一遍。我目前的做法是每个小时检查一次策略进程是否存活、是否正常收到行情推送。持仓变化和成交记录实时推送到手机通知。设置熔断线单日亏损达到账户权益的5%自动将所有持仓平仓并暂停策略24小时。熔断机制是我从2022年的一次事故里学到的。当时ETH在短时间内快速拉升RSI策略连续开了三次空单三次都被止损单日亏损逼近8%。虽然风险比例设计让单日亏损不至于致命但情绪上的打击会直接影响后续交易判断。自动化熔断能强制你远离交易界面等情绪平复后再复盘。5.4 关于资金费率的一些实操体会如果你想长期跑空头策略资金费率必须仔细跟踪。ETH永续合约的资金费率可以在历史数据上拉出来看计算策略持仓期间的平均费率成本把它从回测收益里扣掉。遇到费率极端偏高的时候我甚至会主动暂停空头策略——比如费率年化超过30%时持仓成本已经高到吃掉大部分预期收益此时空头策略的性价比就很低了。在实盘参数上我还会对ETH质押收益率保持关注因为质押收益率会影响市场参与者的做多/做空倾向。当质押收益率处于高位时吃资金费率的做多方有动力持续持仓空头面对的正向资金费率压力会更大。这是一种市场结构层面的成本不能只在策略代码里看到买和卖。回到策略本身如果你打算用这套RSI空头框架我个人的建议是先用至少一年的历史数据把回测跑通确认你能接受42%左右的胜率和20%以内的回撤再去碰实盘小仓位。我在实盘跑这套策略两年多最大的体会是——RSI空头策略赚的不是预测准确率而是你在信号出现时有没有严格执行每一笔止损和止盈。策略代码是公开的但执行纪律属于你自己。
返回列表