固化价格动作止损或固化 RSI(智能止损)·进阶篇
「用最近N根极值动态挂止损的卖单逻辑」
这段开仓调用把卖单止损设成「20点缓冲 + 前一根ATR」,止盈则取入场价与最近最高蜡烛间距的两倍,属于零硬止损加波动自适应止盈的写法。 trade.Sell(theLotsize,_Symbol,Bid,(stoplossforSell(20)+atr[1]),Bid-(2*MathAbs(((stoplossforSell(20)+atr[1]))-Bid)),NULL); stoplossforSell(20) 会扫描最近20根蜡烛,返回最高价所在那根的高点;配合 atr[1](前一根ATR值)后,止损线随波动率拉伸。若ATR在EURUSD的M15上常驻于8~15点区间,实际止损距离可能落在28~35点。 stoplossforBuy 与 stoplossforSell 结构对称:前者用 CopyLow + ArrayMinimum 抓最低蜡烛低点,后者用 CopyHigh + ArrayMaximum 抓最高蜡烛高点。两者都先 ArraySetAsSeries 把序列倒排,保证索引0是当前蜡烛。 外汇与贵金属杠杆高,这类靠极值挂止损的出场在单边毛刺行情中可能连续被扫,上MT5用策略测试器跑近3个月数据验证触发频率再实盘。
trade.Sell(theLotsize,_Symbol,Bid,(stoplossforSell(class="num">20)+atr[class="num">1]),Bid-(class="num">2*MathAbs(((stoplossforSell(class="num">20)+atr[class="num">1]))-Bid)),NULL); class=class="str">"cmt">//Sell Entry with zero stoploss && take profit is twice the distance between the entry and the highest candle } class="type">class="kw">double stoplossforBuy(class="type">int numcandle) { class="type">int LowestCandle; class=class="str">"cmt">//Create array for candle lows class="type">class="kw">double low[]; class=class="str">"cmt">//Sort Candle from current downward ArraySetAsSeries(low,true); class=class="str">"cmt">//Copy all lows for class="num">100 candle CopyLow(_Symbol,_Period,class="num">0,numcandle,low); class=class="str">"cmt">//Calculate the lowest candle LowestCandle = ArrayMinimum(low,class="num">0,numcandle); class=class="str">"cmt">//Create array of price class="type">MqlRates PriceInfo[]; ArraySetAsSeries(PriceInfo,true); class=class="str">"cmt">//Copy price data to array class="type">int Data = CopyRates(Symbol(),Period(),class="num">0,Bars(Symbol(),Period()),PriceInfo); class="kw">return PriceInfo[LowestCandle].low; } class="type">class="kw">double stoplossforSell(class="type">int numcandle) { class="type">int HighestCandle; class="type">class="kw">double High[]; class=class="str">"cmt">//Sort array downward from current candle ArraySetAsSeries(High,true); class=class="str">"cmt">//Fill array with data for class="num">100 candle CopyHigh(_Symbol,_Period,class="num">0,numcandle,High); class=class="str">"cmt">//calculate highest candle HighestCandle = ArrayMaximum(High,class="num">0,numcandle); class=class="str">"cmt">//Create array for price class="type">MqlRates PriceInformation[]; ArraySetAsSeries(PriceInformation,true); class=class="str">"cmt">//Copy price data to array class="type">int Data = CopyRates(Symbol(),Period(),class="num">0,Bars(Symbol(),Period()),PriceInformation); class="kw">return PriceInformation[HighestCandle].high; } class="type">void OnTick() {
无持仓时怎么算出每点价值并触发策略
在 MT5 的 EA 主循环里,先抓取当前品种的报价精度与账户余额,是无持仓分支判断的前置动作。下面这段逻辑只做一件事:把每 pip 对应的账户货币价值算清楚,并确认当前没有敞口。 核心算式利用了 SYMBOL_TRADE_TICK_VALUE 与 SYMBOL_TRADE_TICK_SIZE 的比值,再乘上 point。也就是说,若某品种 tick_size 是 0.00001、tick_value 是 1.0,point 同为 0.00001,则 pipValue 直接等于 1.0 账户货币每点——贵金属与外汇交叉盘要各自核对,不能默认同值。 Balance 用 AccountInfoDouble(ACCOUNT_BALANCE) 实时取,避免用缓存变量导致仓位百分比算错。 只有当 PositionsTotal() 返回 0,才调用 Strategy() 进入信号判断;已有单时整段跳过,降低重复开仓概率。外汇与贵金属杠杆高,实盘前请在策略测试器用不同点值品种各跑一遍验证。
pipValue = (((((SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))*point)/(SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)))); Balance = AccountInfoDouble(ACCOUNT_BALANCE); if (PositionsTotal()==class="num">0) { Strategy(); } }
◍ 用 RSI 极值当隐形止损的入场写法
这套 EA 的做多和做空函数都没有在 trade.Buy / trade.Sell 里填数值止损,而是把止损逻辑外置到 RSI 子窗口里。进场同时用 ObjectCreate 画一条水平线,线价取自 lowestRSI(10) 或 highestRSI(10),相当于把 RSI 级别当成动态止损参考。 仓位计算沿用风险百分比:以账户余额乘 risk,再除以「入场价与 smart stop 距离 ×100 × 点值」得出手数,NormalizeDouble 到 2 位小数。外汇与贵金属杠杆高,这类零硬止损策略回撤可能突然放大,实盘前务必在 MT5 策略测试器跑一遍。 下面这段是核心入场与 RSI 极值抓取代码,注意 CopyBuffer 都缓冲了 200 根柱,但 lowestRSI 只比前 count=10 根。 别把 RSI 线当硬止损 代码里 stoploss 传参是 0,真正风控靠的是你盯那条 RSI 水平线破位手动或另写逻辑平仓;直接以为 EA 会自动止损就错了。
<span class="keyword">class="type">int</span> RSI; <span class="keyword">class="kw">input</span> <span class="keyword">class="type">int</span> rsi = <span class="number">class="num">5</span>; <span class="comment">class=class="str">"cmt">// RSI VAlue</span> <span class="keyword">class="type">class="kw">double</span> lowestrsiValue = <span class="number">class="num">100</span>; <span class="keyword">class="type">class="kw">double</span> highestrsiValue = <span class="number">class="num">0.0</span>; <span class="keyword">class="type">int</span> <span class="functions">OnInit</span>() { <span class="comment">class=class="str">"cmt">//RSI</span> RSI = <span class="indicators">iRSI</span>(<span class="predefines">_Symbol</span>,<span class="predefines">_Period</span>,rsi,<span class="macro">PRICE_CLOSE</span>); } <span class="keyword">class="type">void</span> Buy(<span class="keyword">class="type">class="kw">double</span> Ask) { <span class="keyword">class="type">class="kw">double</span> atr[]; <span class="functions">ArraySetAsSeries</span>(atr,<span class="macro">true</span>); <span class="comment">class=class="str">"cmt">//This array is use to store all ATR value to the last closed bar</span> <span class="functions">CopyBuffer</span>(ATR,<span class="number">class="num">0</span>,<span class="number">class="num">0</span>,<span class="number">class="num">200</span>,atr); <span class="comment">class=class="str">"cmt">// This method copy the buffer value of the ATR indicator into the array(class="num">200 buffered data)</span> theLotsize = <span class="functions">NormalizeDouble</span>((Balance*risk)/((<span class="functions">MathAbs</span>(Ask-((stoplossforBuy(<span class="number">class="num">20</span>)-atr[<span class="number">class="num">1</span>])))*<span class="number">class="num">100</span>)*pipValue),<span class="number">class="num">2</span>); <span class="comment">class=class="str">"cmt">// This Calculate the lotsize class="kw">using the % to risk</span> <span class="functions">ObjectCreate</span>(<span class="number">class="num">0</span>,<span class="class="type">class="kw">string">"sl"</span>,<span class="macro">OBJ_HLINE</span>,<span class="number">class="num">3</span>,<span class="number">class="num">0</span>,lowestRSI(<span class="number">class="num">10</span>)); <span class="comment">class=class="str">"cmt">// Since our stoploss is zero we assign a smart stoploss on the rsi by drawing a line on the rsi window</span> trade.Buy(theLotsize,<span class="predefines">_Symbol</span>,Ask,<span class="number">class="num">0</span>,Ask+(<span class="number">class="num">2</span>*<span class="functions">MathAbs</span>(Ask-((stoplossforBuy(<span class="number">class="num">20</span>)-atr[<span class="number">class="num">1</span>])))),<span class="macro">NULL</span>);<span class="comment">class=class="str">"cmt">//Buy Entry with zero stoploss && take profit is twice the distance between the entry and the lowest candle</span> <span class="functions">Print</span>(<span class="class="type">class="kw">string">"SL"</span>,lowestRSI(<span class="number">class="num">10</span>)); } <span class="keyword">class="type">void</span> Sell(<span class="keyword">class="type">class="kw">double</span> Bid) { <span class="keyword">class="type">class="kw">double</span> atr[]; <span class="functions">ArraySetAsSeries</span>(atr,<span class="macro">true</span>); <span class="comment">class=class="str">"cmt">//This array is use to store all ATR value to the last closed bar</span> <span class="functions">CopyBuffer</span>(ATR,<span class="number">class="num">0</span>,<span class="number">class="num">0</span>,<span class="number">class="num">200</span>,atr); <span class="comment">class=class="str">"cmt">// This method copy the buffer value of the ATR indicator into the array(class="num">200 buffered data)</span> theLotsize = <span class="functions">NormalizeDouble</span>((Balance*risk)/((<span class="functions">MathAbs</span>(Bid-((stoplossforSell(<span class="number">class="num">20</span>)+atr[<span class="number">class="num">1</span>])))*<span class="number">class="num">100</span>)*pipValue),<span class="number">class="num">2</span>); <span class="comment">class=class="str">"cmt">// This Calculate the lotsize class="kw">using the % to risk</span> <span class="functions">ObjectCreate</span>(<span class="number">class="num">0</span>,<span class="class="type">class="kw">string">"sl"</span>,<span class="macro">OBJ_HLINE</span>,<span class="number">class="num">3</span>,<span class="number">class="num">0</span>,highestRSI(<span class="number">class="num">10</span>)); <span class="comment">class=class="str">"cmt">// Since our stoploss is zero we assign a smart stoploss on the rsi by drawing a line on the rsi window</span> trade.Sell(theLotsize,<span class="predefines">_Symbol</span>,Bid,<span class="number">class="num">0</span>,Bid-(<span class="number">class="num">2</span>*<span class="functions">MathAbs</span>(((stoplossforSell(<span class="number">class="num">20</span>)+atr[<span class="number">class="num">1</span>]))-Bid)),<span class="macro">NULL</span>);<span class="comment">class=class="str">"cmt">//Sell Entry with zero stoploss && take profit is twice the distance between the entry and the highest candle</span> <span class="functions">Print</span>(<span class="class="type">class="kw">string">"SL"</span>,highestRSI(<span class="number">class="num">10</span>)); } <span class="keyword">class="type">class="kw">double</span> lowestRSI(<span class="keyword">class="type">int</span> count) { <span class="keyword">class="type">class="kw">double</span> thersi[]; <span class="functions">ArraySetAsSeries</span>(thersi,<span class="macro">true</span>); <span class="functions">CopyBuffer</span>(RSI,<span class="number">class="num">0</span>,<span class="number">class="num">0</span>,<span class="number">class="num">200</span>,thersi); <span class="keyword">for</span> (<span class="keyword">class="type">int</span> i = <span class="number">class="num">0</span>; i<count;i++) { <span class="keyword">if</span> (thersi[i]<lowestrsiValue) { lowestrsiValue = thersi[i]; } }
「用极值 RSI 动态挂止损的逻辑」
这段函数负责在进场后抓取一段窗口内的最高 RSI 值,用来给智能止损提供参考位。外汇与贵金属波动剧烈,RSI 极值往往对应短期动能衰竭,借它挪止损可能比固定点数更贴合行情。 函数先声明 thersi 数组并设为时间倒序,再从 RSI 指标句柄拷贝最近 200 根 K 线的数值。随后用 for 循环遍历前 count 根,只要当前 RSI 大于记录值就更新 highestrsiValue,最后返回该峰值。 在 MT5 里把 count 设成你持仓关注的根数(如 50),跑一遍就能看到进场后 RSI 最高点,据此手动或自动移动止损。注意这仅是概率性辅助,不代表回撤必然受限,实盘仍属高风险。
class="type">class="kw">double highestRSI(class="type">int count) { class="type">class="kw">double thersi[]; ArraySetAsSeries(thersi,true); CopyBuffer(RSI,class="num">0,class="num">0,class="num">200,thersi); for (class="type">int i = class="num">0; i<count;i++) { if (thersi[i]>highestrsiValue) { highestrsiValue = thersi[i]; } } class="kw">return highestrsiValue; }
RSI 止损能否躲开猎杀
这一节只做一件事:验证 RSI 止损 EA 是不是比经典固定止损 EA 更少被扫损。思路很直接,把两种逻辑的回测结果拉到同一张表里比止损触发频率。 测试全部跑在 M1 周期上。分钟级数据能把瞬时插针暴露得最干净,猎杀通常发生在流动性薄、秒级波动放大的那一刻,所以选 M1 而不是 H1 或更高级别。 要复现的话,先在 MT5 策略测试器里分别加载经典止损 EA 与 RSI 止损 EA,品种选你常做的贵金属或直盘,时间帧锁 M1,跑完看交易历史里的止损成交笔数差值。外汇与贵金属杠杆高,M1 假突破扫损概率本来就偏大,结论只能说「可能降低」而非根除。
◍ RSI 止损 EA 的实跑参数清单
下面这组参数是一套名为 MACD_Smart_Stoploss 的智能系统在 Deriv Limited 账户上的实跑配置,品种为 Volatility 10 Index,周期 M1,回测区间 2021.07.01–2021.07.15。 初始本金 500.00 USD,杠杆 1:500,货币 USD。这类高杠杆的小指数品种波动剧烈,实盘前务必在策略测试器里用相同区间复算一遍。 核心输入里 rsi=14、atrValue=20 决定止损带宽,movAvgTrend=200 与 movAvgDirection=50 分别管趋势与方向过滤,MACD 三参数 fast=12、slow=26、signal=9 是经典组合,risk=0.05 表示每单风险约占总资金的 5%。 把这套数字直接拷进 MT5 的 EA 输入栏,先跑 2021 年 7 月那两周,看成交频率和最大回撤是否匹配你的承受能力。