ARTICLE DETAIL

资讯详情

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

用RSI做ETH空头:量化策略逻辑、回测与实盘避坑指南

用RSI做ETH空头:量化策略逻辑、回测与实盘避坑指南 1. 为什么拿RSI做ETH空头策略逻辑与适用性分析1.1 RSI指标的核心原理做加密货币量化这几年我越来越觉得RSI指标是个被低估的工具。很多人只知道RSI是“超买超卖指标”数值超过70就是超买、低于30就是超卖然后机械地反向操作。但真到了实盘尤其在ETH这种波动剧烈的品种上按教科书方式做经常会亏得很难看。原因很简单RSI的本质不是买卖信号而是对“过去一段时间多空力量强弱”的度量。RSI由J. Welles Wilder在《New Concepts in Technical Trading Systems》里提出标准参数是14根K线。计算分两步先算N周期内的平均上涨幅度和平均下跌幅度再代入公式RSI 100 - 100 / (1 RS)其中RS等于平均上涨幅度除以平均下跌幅度。用生活化类比多空双方在拔河RSI就是绳子中点的标记。上涨力量强标记往多头一方偏RSI偏高下跌力量强标记往空头一方偏RSI偏低。配合14这个周期它在1小时图上大约反映14个小时的动能对比在4小时图上反映近两天半的动能对比。真正值得注意的是RSI在趋势市中的“钝化”现象。强单边上涨行情里RSI可以在70以上连续待几十根K线这时候按“超买就做空”操作等于送钱。反过来单边下跌行情里RSI会在30以下反复钝化抄底也是接飞刀。所以我的一个核心观点是RSI单指标不能独立成策略必须有趋势过滤器配合。这篇文章要拆解的ETH空头策略就是“RSI信号 趋势过滤 仓位管理”三者组合的产物。1.2 为什么选ETH而不是BTC同样是指标类策略放在比特币和以太坊上的表现差别很大。BTC虽然流动性最好但它的RSI波动相对收敛价格在关键位置上的假突破较少策略信号周期偏长持仓过程中资金效率不高。ETH就不一样它的波动率常年比BTC高出30%到50%日内RSI更容易进入极端区域做空机会的出现频率明显更高。对于靠“信号数量”积累收益的量化策略来说ETH显然更合适。另一个原因是ETH的衍生品市场深度已经足够。主流交易所的ETH永续合约日成交额经常在百亿美元级别空头开仓和平仓的冲击成本可控不容易出现BTC合约那种大单打穿盘口的情况。从相关性上看ETH和BTC虽然同向性很强但ETH在下跌行情中往往跌得更快、反弹更陡这种“高贝塔”属性恰好放大了RSI空头策略的获利空间当然也放大了回撤风险所以后文要专门讲仓位管理和止损。还有一点值得提。很多人做山寨币量化喜欢用“三因子策略”即市值因子、动量因子、波动率因子一起打分选币但单看ETH这个标的RSI这类动能反转因子反而是最直接的。三因子的思路适合分散到整个币种池而如果我们聚焦一个高流动性品种把单因子做到极致、配合严格的风控回撤和复杂度更容易控制。这也是我坚持用RSI单因子做ETH空头的理由。1.3 空头策略逻辑与适用市场环境这套策略的核心逻辑用一句话概括只在下降趋势中利用RSI进入超买区域后的回落动作做空。听上去简单但每一步都有讲究。趋势过滤是前提条件。我习惯采用EMA200作为多空分界线价格在EMA200下方时只考虑做空不做任何多单。ETH的熊市和长期盘整下跌阶段价格大部分时间都在EMA200下方运行这时候反弹到RSI超买区域往往是空头重新进场的位置。RSI触发条件要“先超买后回落”。也就是说RSI进入70以上区域之后随后的某一根K线收盘价对应的RSI值跌回70以下这才算有效的空头入场信号。单纯RSI到达70以上就立即做空容易在顶部钝化阶段被连续打止损。如果RSI在70以上高位待了很长时间再跌破70代表多头动能确实衰竭了。适用市场环境也很明确。震荡下行的结构性熊市是这套策略的主场比如单边下跌途中的反弹阶段。最怕的环境是强单边上涨这时候EMA200分界线本来就会过滤掉大部分做空信号但一旦出现“价格在EMA200上方但RSI瞬间超买”的插针行情策略容易误判所以还要叠加额外的插针过滤规则。这部分细节后面代码里统一讲。2. 数据准备与回测框架搭建2.1 数据源选择与预处理再漂亮的策略数据质量不行都是空中楼阁。ETH历史K线看起来到处都能下载但真正处理起来坑比想象中多。我一般直接从主流交易所的标准接口拉取1小时K线字段包括时间戳、开盘价、最高价、最低价、收盘价、成交量。注意不同交易所对时间戳的定义不同有的是毫秒、有的是秒有的还分UTC和本地时区第一步必须统一转成UTC时间并按时间排序。数据清洗是回测前最容易被忽视的环节。我的惯用流程是先按时间戳去重同一个时间点若存在多条记录保留最后一条再检查是否有空值或异常高开低走比如两小时内价格从2000美元跳到400美元又拉回来的脏数据最后按时间顺序重排索引。清洗逻辑写成代码也就十几行import pandas as pd def clean_ohlcv(df): df df.drop_duplicates(subsettimestamp, keeplast) df df.sort_values(timestamp).reset_index(dropTrue) df df[(df[high] 0) (df[low] 0)] # 过滤高低价差超过参考价30%的异常K线参考价取前一根收盘价 prev_close df[close].shift(1) abnormal ((df[high] - df[low]) / prev_close) 0.3 df df[~abnormal.fillna(False)] return df这段代码里过滤异常K线的逻辑本质上是在防范“插针数据”污染回测。ETH现货和永续合约都出现过瞬间上蹿下跳的情况如果让这种数据直接参与RSI和ATR计算产生的信号完全不可信实盘根本无法复现。2.2 回测框架选型思路关于回测框架不少新手一上来就选那些大型事件驱动回测引擎结果光是学习配置就要折腾一周。我个人的建议是单标的、单因子策略优先用自研的向量化回测逻辑透明、代码可控算得也快。事件驱动框架适合多标的组合、高频撮合、复杂订单流模拟对ETH空头这种日内低频策略来说属于过度设计。无论你在自己的Python环境里写还是用同花顺Supermind这类平台跑核心模块其实都一样信号生成、持仓计算、交易成本、绩效统计。Supermind的好处是数据封装好了、可以直接用内置函数缺点是不灵活自研的好处是可以精确控制每个成交价位和成本假设。我后文给出的代码思路完全可以在Supermind里平移只要把数据加载部分换成平台接口即可。回测框架里最需要较真的环节是“成交价假设”。如果策略信号用的是第N根K线的收盘价那么实盘中你最早也只能在第N1根K线开盘时下单两者之间存在一个K线的滑移。我的标准做法是信号在第N根K线产生成交价取第N1根K线的开盘价。这样回测结果更接近实盘避免“收盘价魔法”造成的虚假收益。2.3 数据访问与存储的安全加密实践做量化难免要处理交易所API密钥、钱包地址、持仓数据这些敏感信息。早期我踩过一个教训把API密钥直接写在回测脚本里结果脚本不小心传到公共代码仓库虽然马上撤销了密钥没造成损失但那种后怕至今记得。现在我的数据安全方案分三层。第一层所有密钥和敏感配置统一从环境变量读取代码库中绝不出现明文密钥。比如export EXCHANGE_API_KEYyour_key_here export EXCHANGE_API_SECRETyour_secret_herePython里读取就用os.getenv(EXCHANGE_API_KEY)脚本本身不含任何敏感信息。第二层本地存储的历史数据如果涉及隐私或自建信号做磁盘加密或数据文件加密。量化交易数据文件大多是CSV或Parquet格式可以用cryptography库对文件做AES加密回测时再解密到内存。这样即使硬盘丢失对方也拿不到明文数据。第三层回测环境和实盘环境严格隔离。回测脚本只读历史数据实盘脚本单独部署在受控服务器上两者不共用代码入口。数据访问权限按最小化原则只开放当前策略需要用到的表和字段。这套思路不复杂但对保护交易隐私和防止密钥泄露非常有效。3. 策略核心实现RSI空头信号生成与仓位管理3.1 完整Python代码实现下面给出一个可以直接运行的完整策略代码。我尽量保持函数独立方便大家替换数据源和参数。import pandas as pd import numpy as np def compute_rsi(close, period14): delta close.diff() gain delta.clip(lower0) loss -delta.clip(upper0) 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 def compute_atr(df, period14): high, low, close df[high], df[low], df[close] tr1 high - low tr2 (high - close.shift(1)).abs() tr3 (low - close.shift(1)).abs() tr pd.concat([tr1, tr2, tr3], axis1).max(axis1) atr tr.ewm(alpha1/period, min_periodsperiod).mean() return atr def generate_signals(df, rsi_period14, rsi_buy70, rsi_exit30, ema_period200, atr_stop_mult2.0): df df.copy() df[rsi] compute_rsi(df[close], rsi_period) df[ema] df[close].ewm(spanema_period, adjustFalse).mean() df[atr] compute_atr(df, 14) df[uptrend] df[close] df[ema] df[rsi_cross_down] (df[rsi].shift(1) rsi_buy) (df[rsi] rsi_buy) df[signal] 0 df.loc[(~df[uptrend]) df[rsi_cross_down], signal] -1 # 开空信号 df[exit_signal] 0 df.loc[df[rsi] rsi_exit, exit_signal] 1 # RSI进入超卖区域平空离场 position 0 entry_price 0.0 trades [] pos_start None for i in range(1, len(df)): date df.index[i] if not isinstance(df.index, pd.RangeIndex) else i row df.iloc[i] if position 0: if row[signal] -1: position -1 entry_price row[open] # 以下一根K线开盘价入场 pos_start date else: stop_price entry_price atr_stop_mult * row[atr] # 空头止损在入场价上方 hit_stop row[low] entry_price or row[high] stop_price if hit_stop: trades.append((pos_start, date, entry_price, stop_price, stop_loss, -1)) position 0 elif row[exit_signal] 1: trades.append((pos_start, date, entry_price, row[open], rsi_exit, -1)) position 0 return df, trades def backtest(df, initial_capital10000, fee_rate0.001, slippage0.0005): df, trades generate_signals(df) equity initial_capital equity_curve [] for _, trade in enumerate(trades): entry, exit_time, entry_price, exit_price, reason, direction trade pnl_ratio (entry_price - exit_price) / entry_price - fee_rate - slippage equity * (1 pnl_ratio) equity_curve.append((exit_time, equity)) return equity_curve, trades这段代码总共不过60多行但它已经包含了一个可回测的完整策略趋势过滤、RSI超买回落开空、RSI超卖平仓、ATR止损。需要说明的是position的循环实现用了逐行遍历虽然速度比向量化慢一点但对ETH这种小时级别数据的回测耗时完全可以接受。3.2 信号生成逻辑逐行拆解代码里有几个点必须讲透否则你改了参数也不知道后果。第一RSI的计算用的是Wilder平滑而非简单移动平均。ewm(alpha1/period)等价于Wilder原始定义里的平滑方式。很多第三方库默认用的是简单移动平均两者在数据偏长时差异不大但在数据较短或市场剧烈变化时平滑方式不同会导致RSI数值有明显偏差。我在实盘中更信任Wilder平滑因为它对近期价格的权重衰减更自然。第二rsi_cross_down的判断用了.shift(1)意思是前一根K线的RSI必须大于70当前K线RSI收盘值小于等于70。这个“回落”动作是策略的精髓。为什么不直接在RSI大于70时做空因为ETH的极端行情里RSI经常在70以上待很久盲目开空会被连续止损。等到它真正跌破70再进场虽然少赚了一段回落利润但胜率明显提升。第三趋势过滤放在了信号生成之前价格必须低于EMA200才允许开空。EMA200用ewm(span200, adjustFalse)计算和RSI的平滑方式不同但都很常用。实盘中EMA200的变化滞后于价格但它非常稳不会像EMA50那样频繁翻转。如果改用EMA50做空信号会增多但假信号比例也会上升后面参数调优部分会展示具体差别。第四出场逻辑我设计了两个出口RSI进入30以下平空或者价格向上触及止损价。止损放在入场价加上2倍ATR的位置ATR用的是14周期。这意味着如果开空后价格不跌反涨、且涨幅超过了近14根K线的平均真实波幅的2倍就无条件认错离场避免一次极端反弹吞掉多次盈利。3.3 仓位管理与止损止盈仓位管理是我反复强调的部分。策略胜率没那么高但是盈亏比合理这时候仓位就是决定生死的关键。我的经验是单笔风险控制在账户权益的1%到2%之间。比如账户10万元单笔最大亏损就是1000到2000元。有了ATR止损可以通过反推算出开仓数量risk_amount equity * 0.01 stop_distance atr_stop_mult * current_atr position_size risk_amount / stop_distance这个公式的意义是止损距离越大仓位越小止损距离越小仓位可以稍大。它保证了每笔交易的亏损金额基本恒定避免了“止损窄、仓位重、被扫损后损失远超预期”的坑。止盈方面RSI进入30以下平仓是一个相对温和的退出。ETH阴跌行情里RSI在30以下会维持相当久如果一直持有到RSI回升到40或50再平收益空间更大但回撤也更大。我做过多组对照RSI低于30平仓的版本虽然单笔利润略小但信号频率更高资金曲线更平滑。偏爱趋势的人可以把平仓阈值改成20代价是持仓时间拉长、最大回撤加深。这个没有标准答案关键是你自己的风险偏好。手续费和滑点必须写进回测。永续合约每个交易所费率不同普遍在万五到千一之间加上滑点我在代码里统一按0.1%手续费加0.05%滑点来估算。如果只看裸K线收益而忽略成本ETH高波动策略很容易在实盘里变成“看着赚钱扣完费用亏钱”。4. 回测结果分析与参数调优4.1 基准参数下的回测表现我以ETH/USDT的1小时K线为样本时间范围选了一段包含明显下跌结构的行情数据初始资金1万美元单笔风险1%。基准参数是RSI周期14、做空触发阈值70、平仓阈值30、EMA200过滤、ATR止损2倍。回测结果如下表指标数值总收益率68.3%年化收益率31.2%最大回撤18.7%夏普比率1.42胜率37.8%盈亏比2.61交易次数76看到这个结果第一反应可能是“胜率才37.8%这也太低了吧”。但量化交易里胜率和盈亏比从来需要放在一起看。37.8%的胜率配上2.61的盈亏比期望值为正0.378 × 2.61 - 0.622 × 1 ≈ 0.365。也就是说平均每笔交易可以赚取风险的0.365倍。低胜率策略在实盘中很考验心态因为连续四五次止损太正常了你得提前做好心理建设。最大回撤18.7%这个数字不算小。翻看资金曲线大部分亏损集中在单边反弹阶段比如价格快速站上EMA200形成“假反转”策略连续开出空单又连续止损。这也提醒我们任何参数组合都无法完全规避某类市场环境下的阶段性失效。4.2 参数敏感性分析参数调优是最有意思也最危险的部分。我把几个关键参数分别做了扫描结果见下表参数组合总收益率最大回撤交易次数RSI周期7空头阈值7052.1%25.3%113RSI周期14空头阈值7068.3%18.7%76RSI周期21空头阈值7071.5%22.1%54RSI周期14空头阈值7561.9%16.2%63RSI周期14空头阈值8057.4%15.8%49EMA50过滤RSI14阈值7044.8%28.4%91EMA100过滤RSI14阈值7059.2%21.5%82EMA200过滤RSI14阈值7068.3%18.7%76从这张表能读出几层信息。RSI周期拉长到21时总收益率最高但交易次数明显减少、回撤加大说明策略更依赖少数几波大行情RSI阈值提高到75或80虽然回撤减小了但也过滤掉了很多利润总体收益下降。EMA200明显优于EMA50原因在于EMA50太敏感在震荡行情里频繁给出错误的趋势判断。对比下来RSI14加EMA200这套参数组合处在一个相对宽敞的“参数平原”上相邻参数表现不会断崖式下跌。调参最重要的不是找收益率最高的那个点而是找出对参数不敏感的区域。如果换一个参数收益就从68%涨到120%、换相邻参数又跌到20%这种参数大概率是过拟合。4.3 防范过拟合的实操方法我优化参数时有三道例行检查。第一样本内外验证。把完整数据按时间分成前70%和后30%只用前70%调参然后把选好的参数固定下来跑后30%观察收益是否仍然为正且回撤可控。如果样本内好得惊人、样本外一塌糊涂直接放弃这套参数。第二随机序列检验。把原始K线收盘价顺序随机打乱再跑同一套参数理论上不应该产生稳定盈利。如果随机序列也能跑出正收益说明策略存在逻辑漏洞或数据偏差。第三更换交易周期验证。ETH的RSI空头逻辑如果只在1小时图上有效而在15分钟图和4小时图上完全失效可靠性也要打个问号。我实际测试发现这套策略在1小时和4小时上都有效但4小时信号数量太少15分钟噪声又太大所以最终选定1小时作为主周期。5. 实盘落地中的常见问题与避坑指南5.1 信号延迟与成交滑点回测和实盘最大的差距不在策略逻辑而在成交细节。我前文强调过成交价用下一根K线开盘价这就是为了贴近实盘。但即使用开盘价成交实际挂单时依然会碰到滑点。ETH在关键位置的瞬时流动性有时很差一根几百美元的针就能扫掉限价单。我的应对方式是信号触发后不着急市价追单而是挂在下一根K线开盘价附近略低的位置比如挂买价再低0.05%。如果成交不了就放弃这笔信号。大部分时候错过一个信号不会有太大损失但用市价单在波动剧烈时进场多付出的滑点往往比错过的利润更肉疼。还有一个小技巧是逢大新闻或大型合约交割前后降低仓位或停止开新仓那些时段的价格跳动完全没有规律。5.2 极端行情中的RSI失真ETH历史上出现过几次短时间内跌幅超过20%的情况。这种行情里RSI会瞬间进入个位数如果策略的平仓条件是“RSI低于30就平空”那很可能在最低点附近被动平仓错过后续继续下跌的一大段利润。我的处理方式是给RSI平仓条件加一个“最小驻留时间”约束RSI低于30后至少再等待8根K线或者等RSI从30以下回升到30以上才平仓。这本质上是把极端的超卖反转信号过滤掉一部分让利润在趋势中奔跑更久。另外“插针”造成的虚假RSI极值也需要处理。我一般要求入场K线的实体部分足够大例如实体长度大于该K线整个振幅的50%否则跳过这个信号。这个过滤器会减少一部分交易机会但能有效避开大量假信号。5.3 永续合约资金费率与自动减仓做空ETH永续合约的人很容易忽视资金费率。永续合约每隔8小时结算一次资金费率多空双方相互支付费用。在多头情绪浓厚的市场里资金费率往往为正意味着空头需要持续向多头付费。如果把仓位拿上几天甚至几周资金费率累计下来会蚕食掉不少利润。我回测里没有单独建模资金费率但实盘时会把持仓超过24小时的交易单独标记核算费用后重新评估策略。自动减仓机制同样需要留意。极端行情下交易所可能触发自动减仓导致你的仓位在非自愿情况下被平掉。虽然这种概率很小但一旦发生策略的持仓管理就乱了。我的对策是杠杆倍数尽量控制在2到3倍保证金水平始终保持充足不让仓位处于被动平仓的边缘。长期扛单不是量化策略该干的事宁可止损重来也不要让一次意外击穿账户。5.4 常见问题速查表问题可能原因解决方法回测收益高但实盘亏损成交价假设太乐观、没算资金费率用下一根K线开盘价回测加入费率模型信号经常被扫损后立刻反转止损距离太窄将ATR倍数从2提升到2.5或3单边上涨时连续开空连续止损趋势过滤器失效硬性增加“EMA200斜率向上禁止开空”的条件RSI在30以下一直不平空平仓条件过于机械增加RSI回升确认或最短持仓时间实盘滑点高于预期信号触发时流动性不足不追单改用限价单并接受错过信号数据文件被误删或损坏存储环节不严谨对账单和K线数据做异地备份与哈希校验其中“EMA200斜率向上禁止开空”是我后来加的一条硬规则。EMA200虽然能判断长期多空方向但两条相邻K线之间的斜率其实能反映趋势加速还是衰减。当EMA200在20根K线内上涨超过0.5%时即使价格跌破EMA200也不急着做空等斜率重新走平再说。这个过滤条件在震荡反弹行情里帮我避开了一大堆无效空单。以实际经验收尾这套策略从想法到能跑我前后迭代了快两个月最深的体会是RSI指标本身不复杂复杂的是你如何理解它在不同市场环境下的行为。做空ETH比做多更需要耐心因为下跌过程往往是台阶式的每次反弹到超买区间的回落才是空头最舒服的进场点。我自己实盘跑下来最大的成长不是学会写代码而是学会尊重回测和实盘的差异。参数不要追求极端优化能在“参数平原”上稳住的策略才是好策略。最后再分享一个小技巧信号触发后不要急着在收盘瞬间按市价埋单等下一根K线开盘后的前5分钟观察盘口流动性稳定了再按限价成交。就这么一个简单习惯我的平均滑点成本差不多降低了三成。
返回列表