English Русский Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
固化价格动作止损或固化 RSI(智能止损)

固化价格动作止损或固化 RSI(智能止损)

MetaTrader 5示例 | 14 二月 2022, 10:51
3 439 0
vwegba
vwegba

概述

为了寻找交易圣杯,导致我进行了这项研究。 当涉及资金管理时,止损是交易中最重要的工具。 资金管理是交易者在市场上赚钱、及维持长久的不同方式之一。 如前所述,资金管理与止损和风险回报率密切相关。 与其它的(风险:回报)比值相较,1:1.5R 往往胜率更高,但大多数时候 1:>1.9R 的比值往往更可盈利,且交易者在很长一段时间内能持续盈利(圣杯)。 该“圣杯”交易策略有其不利之处。 在理想情况下,如果在 10 笔交易(每笔交易 1 个点)中,有 6 笔交易失利(6 个点),4 笔交易获利(8 个点),那么 1:>1.9R(风险:回报)的交易即有利可图。 这意味着我们的利润只有 2 个点。 在实际应用中,这可能并不全是真实的。 造成这种情况的一个主要因素是一个被称为 “止损猎杀(Stop-loss Hunt)”的术语。 止损猎杀是指当一笔交易因流动性触发您的止损,然后再向您预测的方向移动。 止损猎杀是交易和资金管理中的一个主要难题。 它还让交易者(主要是新交易者)产生心理影响。 

止损猎杀(Stop-loss Hunt)

图例 1.1. 止损猎杀(Stop-loss Hunt)

止损猎杀主要与价格动作或烛条图表上的固化或尾随止损有关。 如果价格动作图表上没有止损,就不会有止损猎杀。 但是止损为零,则等同于您的交易账户爆仓的概率(等于 1)。


RSI 止损

RSI 振荡器是在限定 100 到 0 范围的窗口里绘制的价格动作折线图的复制品

thRsi


图例 1.2. RSI 和折线图表

如果 RSI 指标和折线图表非常近似,那么利用 RSI 指标作为智能止损可能会降低止损猎杀的风险。

标的:

于此,我的目标是验证采用 RSI 止损是否能够降低止损猎杀,以及综上所有长久运作时能否有利可图。

客观:

相同策略的两种比较:一种是在价格动作图表上设置止损;另一种是基于 RSI 指标设置止损。




策略与代码

在价格动作图表上的经典止损

对于第一个 EA,在价格动作中设置固化止损。 以下是该策略的需求

参数

说明

所用指标

MACD (12,26,9)

所用指标

移动均线 (200)

所用指标

移动均线 (50)

所用指标

ATR (5)

时间帧

1 分钟

入场做多

当 MACD 线和信号线均低于零时,如果移动平均线(50)高于移动平均线(200),且 MACD 线高于信号线

入场做空

当 MACD 线和信号线均高于零时,如果移动平均线(50)低于移动平均线(200),且 MACD 线低于信号线

离场

止盈和止损(1:2R)。

做多条件下的止损是入场后二十(20)根烛条的最低值,减去 ATR(5)的值

而做空条件下的止损是入场后二十(20)根烛条的最高值,加上 ATR(5)的值

 


图示如下所示。

入场做多经典止损


图例 2.1 入场做多

入场做空经典止损


图例 2.2 入场做空

代码

代码的第一部分主要是变量声明和输入数据。 所有指标的句柄变量均在此处声明。

#property copyright "Copyright 2021, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
#include<Trade\Trade.mqh>
CTrade trade;
int MATrend;
int MADirection;
int MACD;
int ATR;
input int afi;// ----------RiskAmount------------
input double risk = 0.02; //% Amount to risk
input int atrValue = 20; // ATR VAlue
input int ai;// ----------Moving Average inputs------------
input int movAvgTrend = 200;// Moving Average Trend
input int movAvgDirection = 50;//moving Average for trend Direction;
input int i;// -----------MACD inputs-----------------------
input int fast = 12;// Macd Fast
input int slow = 26; //Macd Slow
input int signal = 9; //Signal Line

其它变量声明

double pipValue  = 0.0;// 

double Balance; // For the Current Balance

在 init() 函数中,把每个句柄逐一赋值给变量

int OnInit()
  {
//---
      //Moving Averages Indicators''
      MATrend = iMA(_Symbol,_Period,movAvgTrend,0,MODE_SMA,PRICE_CLOSE); //Moving Average 200
      MADirection = iMA(_Symbol,_Period,movAvgDirection,0,MODE_EMA,PRICE_CLOSE); //Moving Average 50
      //MACD
      MACD = iMACD(_Symbol,_Period,fast,slow,signal,PRICE_CLOSE);//MACD 
      //ATR
      ATR = iATR(_Symbol,_Period,atrValue);
      //---
      point=_Point;
      double Digits=_Digits;
      
      if((_Digits==3) || (_Digits==5))
      {
         point*=10;
      }
      return(INIT_SUCCEEDED);
  }


策略如何运行的代码如下所示

void Strategy() {
   MqlRates priceAction[];
   ArraySetAsSeries(priceAction,true);
   int priceData = CopyRates(_Symbol,_Period,0,200,priceAction); 
   
   double maTrend[]; ArraySetAsSeries(maTrend,true);
   CopyBuffer(MATrend,0,0,200,maTrend); //200 MA
     
   double madirection[]; ArraySetAsSeries(madirection,true);
   CopyBuffer(MADirection,0,0,200,madirection);  //50 MA
   
   double macd[]; ArraySetAsSeries(macd,true);
   CopyBuffer(MACD,0,0,200,macd);  //MACD
   
   double macds[]; ArraySetAsSeries(macds,true);
   CopyBuffer(MACD,1,0,200,macds);  //MACD_Signal Line   
      
   double Bid  = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);  
   
   
   if (madirection[1]>maTrend[1]) {
      //Buy ; Uptrend
     
     
      
      bool macd_bZero = macds[1]<0&&macd[1]<0; //MacD Signal Line is less than Zero
      bool macd_cross = macd[1]>macds[1];// Macd Crosses the signal line
      
      if (macd_bZero && macd_cross) {
         buyTrade = true;
      }
      
      
   } else if (madirection[1]<maTrend[1]) {
      //Sell; DownTrend
      
     
      bool macd_bZero = macds[1]>0&&macd[1]>0;; //MacD Signal Line is less than Zero
      bool macd_cross = macd[1]<macds[1];// Macd Crosses the signal line
      
      if (macd_bZero && macd_cross) {
         sellTrade = true;
      }      
      
    }  
    
   if (buyTrade && sellTrade) {
      buyTrade = false;
      sellTrade = false;
   return;
   }
      
      
   if (buyTrade) {
      buyTrade = false;
      sellTrade = false;
      
      Buy(Ask);
   } else if (sellTrade) {
      buyTrade = false;
      sellTrade = false;
      
      Sell(Bid);   
   }
   
}

入场 (做多和做空)

void Buy(double Ask) {
   double atr[]; ArraySetAsSeries(atr,true); //This array is use to store all ATR value to the last closed bar
   CopyBuffer(ATR,0,0,200,atr); // This method copy the buffer value of the ATR indicator into the array (200 buffered data)

   theLotsize =  NormalizeDouble((Balance*risk)/((MathAbs(Ask-((stoplossforBuy(20)-atr[1])))*100)*pipValue),2); // This Calculate the lotsize using the % to risk
   trade.Buy(theLotsize,_Symbol,Ask,(stoplossforBuy(20)-atr[1]),Ask+(2*MathAbs(Ask-((stoplossforBuy(20)-atr[1])))),NULL); //Buy Entry with zero stoploss && take profit is twice the distance between the entry and the lowest candle
    

}
void Sell(double Bid) {
   double atr[]; ArraySetAsSeries(atr,true); //This array is use to store all ATR value to the last closed bar
   CopyBuffer(ATR,0,0,200,atr); // This method copy the buffer value of the ATR indicator into the array (200 buffered data)
   theLotsize =  NormalizeDouble((Balance*risk)/((MathAbs(Bid-((stoplossforSell(20)+atr[1])))*100)*pipValue),2); // This Calculate the lotsize using the % to risk
   trade.Sell(theLotsize,_Symbol,Bid,(stoplossforSell(20)+atr[1]),Bid-(2*MathAbs(((stoplossforSell(20)+atr[1]))-Bid)),NULL); //Sell Entry with zero stoploss && take profit is twice the distance between the entry and the highest candle

}

从上面的代码中,我们调用了两个方法,即 stoplossforSell(int num) 和 stoplossforBuy(int num)。 这两个方法专门用于在触发入场交易后,分别摘选指定数量内的最高和最低烛条。 即,stoplossforSell(20) 返回入场前 20 根烛条中最高的一根。

double stoplossforBuy(int numcandle) {
         int LowestCandle;
         
         //Create array for candle lows
         double low[];
         
         //Sort Candle from current downward
         ArraySetAsSeries(low,true);
         
         //Copy all lows for 100 candle
         CopyLow(_Symbol,_Period,0,numcandle,low);
         
         //Calculate the lowest candle
         LowestCandle = ArrayMinimum(low,0,numcandle);
         
         //Create array of price
         MqlRates PriceInfo[];
         
         ArraySetAsSeries(PriceInfo,true);
         
         //Copy price data to array
         
         int Data = CopyRates(Symbol(),Period(),0,Bars(Symbol(),Period()),PriceInfo);
      
         return PriceInfo[LowestCandle].low;
                  
      
         

}
double stoplossforSell(int numcandle) {
         int HighestCandle;
         double High[];
       
       //Sort array downward from current candle
         ArraySetAsSeries(High,true);
       
       //Fill array with data for 100 candle
         CopyHigh(_Symbol,_Period,0,numcandle,High);
         
         //calculate highest candle
         HighestCandle = ArrayMaximum(High,0,numcandle);
         
         //Create array for price
         MqlRates PriceInformation[];
         ArraySetAsSeries(PriceInformation,true);
         
         
         //Copy price data to array
         int Data = CopyRates(Symbol(),Period(),0,Bars(Symbol(),Period()),PriceInformation);
         
         return PriceInformation[HighestCandle].high;
           
 
 }

该 EA 检查是否存在持仓,如果没有持仓,则调用策略方法入场交易。

void OnTick()
  {
//---
   pipValue  = ((((SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE))*point)/(SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE))));

   Balance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   if (PositionsTotal()==0) {
      Strategy();
   }
  }

基于 RSI 指标的止损


第二个 EA 则基于 RSI 指标采用固化止损。 以下是该策略的需求。

参数

说明

所用指标

MACD (12,26,9)

所用指标

移动均线 (200)

所用指标

移动均线 (50)

所用指标

ATR (5)

时间帧

1 分钟

入场做多

当 MACD 线和信号线均低于零时,如果移动平均线(50)高于移动平均线(200),且 MACD 线高于信号线

入场做空

当 MACD 线和信号线均高于零时,如果移动平均线(50)低于移动平均线(200),且 MACD 线低于信号线

离场

止盈。

做多条件下的止损是入场后二十(10)个 RSI 值中的最低值

而做空条件下的止损是入场后二十(10)个 RSI 值中的最高值

 

如果 RSI 越过最高或最低 RSI,交易平仓。

 


在 RSI 止损上画一条线,便于可视化

入场做多的止损(RSI 止损)


图例 2.3. 做多交易基于 RSI 的止损

如若当前 RSI 值小于 RSI 窗口上的止损线时,交易平仓。

入场做空的止损(RSI 止损)


图例 2.4. 做空交易基于 RSI 的止损

如若当前 RSI 值大于 RSI 窗口上的止损线时,交易平仓。

代码

代码的第一部分主要是变量声明和输入数据。 与第一个指标类似,略微有所添加,示意如下

int RSI;
input int rsi = 5; // RSI VAlue
double lowestrsiValue = 100;
double highestrsiValue = 0.0;

与 onint() 方法类似,略微有所添加,示意如下

int OnInit()
  {
              //RSI
      RSI = iRSI(_Symbol,_Period,rsi,PRICE_CLOSE);
}


该策略的代码与上述相同。 但入场做多和做空都未设止损,因为我们将采用 RSI 级别作为止损。 下面是入场的代码

void Buy(double Ask) {
   double atr[]; ArraySetAsSeries(atr,true); //This array is use to store all ATR value to the last closed bar
   CopyBuffer(ATR,0,0,200,atr); // This method copy the buffer value of the ATR indicator into the array (200 buffered data)

   theLotsize =  NormalizeDouble((Balance*risk)/((MathAbs(Ask-((stoplossforBuy(20)-atr[1])))*100)*pipValue),2); // This Calculate the lotsize using the % to risk
   
   ObjectCreate(0,"sl",OBJ_HLINE,3,0,lowestRSI(10)); // Since our stoploss is zero we assign a smart stoploss on the rsi by drawing a line on the rsi window
   trade.Buy(theLotsize,_Symbol,Ask,0,Ask+(2*MathAbs(Ask-((stoplossforBuy(20)-atr[1])))),NULL);//Buy Entry with zero stoploss && take profit is twice the distance between the entry and the lowest candle
    Print("SL",lowestRSI(10));
}
void Sell(double Bid) {
   double atr[]; ArraySetAsSeries(atr,true); //This array is use to store all ATR value to the last closed bar
   CopyBuffer(ATR,0,0,200,atr); // This method copy the buffer value of the ATR indicator into the array (200 buffered data)
   
   theLotsize =  NormalizeDouble((Balance*risk)/((MathAbs(Bid-((stoplossforSell(20)+atr[1])))*100)*pipValue),2);  // This Calculate the lotsize using the % to risk
   
   ObjectCreate(0,"sl",OBJ_HLINE,3,0,highestRSI(10)); // Since our stoploss is zero we assign a smart stoploss on the rsi by drawing a line on the rsi window
   trade.Sell(theLotsize,_Symbol,Bid,0,Bid-(2*MathAbs(((stoplossforSell(20)+atr[1]))-Bid)),NULL);//Sell Entry with zero stoploss && take profit is twice the distance between the entry and the highest candle
   Print("SL",highestRSI(10));
}


最终的代码与上述 EA 有所区别的地方在于获取 RSI 最低值和最高值的方法。 从上述的入场方法调用,并依据 RSI 的最低或最高点数据绘制一条线。

注:在策略方法中,当没有持仓时,则删除已绘制的线。

 double lowestRSI(int count) {     
      double thersi[]; ArraySetAsSeries(thersi,true);
      CopyBuffer(RSI,0,0,200,thersi);
      
      for (int i = 0; i<count;i++) {
      
         if (thersi[i]<lowestrsiValue) {
            lowestrsiValue = thersi[i];
         }
      }
   return lowestrsiValue;
}
//This method get the Highest RSI afer ENtry to set the smart Stoploss
double highestRSI(int count) {

      
      double thersi[]; ArraySetAsSeries(thersi,true);
      CopyBuffer(RSI,0,0,200,thersi);
      
      for (int i = 0; i<count;i++) {
      
         if (thersi[i]>highestrsiValue) {
            highestrsiValue = thersi[i];
         }
      }
   return highestrsiValue;
}

####

现在,EA 已设置并编译完毕,我们可以继续测试这两个 EA,以便获得所需的结果。


测试和结果

止损猎杀测试

在本章节中,将讲解模拟测试,以及从其获得的结果。 进行的第一项测试是判定 RSI 止损 EA 是否能够降低交易中的止损猎杀问题。 会取其结果与经典的止损 EA 进行比较。

测试在 M1 时间帧内完成。

RSI 止损 EA 入场数据

智能系统: MACD_Smart_Stoploss
品种: Volatility 10 Index
周期: M1 (2021.07.01 - 2021.07.15)
输入: afi=0
risk=0.05
atrValue=20
rsi=14
ai=0
movAvgTrend=200
movAvgDirection=50
i=0
fast=12
slow=26
signal=9
经纪商: Deriv Limited
货币: USD
初始本金: 500.00
杠杆: 1:500



经典止损 EA 入场数据

智能系统: MACD_Cross_Stoploss
品种: Volatility 10 Index
周期: M1 (2021.07.01 - 2021.07.15)
输入: afi=0
risk=0.05
atrValue=5
ai=0
movAvgTrend=200
movAvgDirection=50
i=0
fast=12
slow=26
signal=9

risk reward=1:2
经纪商: Deriv Limited
货币: USD
初始本金: 500.00
杠杆: 1:50


结果

两个 EA 实施的交易图形呈现如下所示。 从每个 EA 中抽取了总计 3 笔交易样品。

RSI 止损 1


图例 3.1. 来自 RSI 止损 EA 的样本 1

价格动作止损


图例 3.1a. 来自经典止损 EA 的样本 1

Rsi 止损 2

图例 3.2. 来自 RSI 止损 EA 的样本 2 1

价格动作止损

图例 3.2a. 来自经典止损 EA 的样本 2

Rsi 止损 3
图例 3.3. 来自 RSI 止损 EA 的样本 3

价格动作止损

图例 3.3a. 来自经典止损 EA 的样本 3


从以上比较中可以看出,与价格动作图表上的经典止损设置相比,RSI 止损 EA 在避免被市场猎杀层面做得非常好。


盈利能力测试

现在是时候问一个大问题“这能盈利吗?”。 鉴于 RSI 止损 EA 在避免止损猎杀方面做得很出色,因此它必须是能盈利的,且具有更高的胜率,因为与经典的止损方法相比,它触发止损的机率更低。 从逻辑上讲,这应该是真实的。 但要证明这一理论,必须进行测试。

两个测试均采用来自上述测试的类似数据。 针对两个 EA,将在 M1 时间帧进行 100 笔交易以上的回测。 以下是结果。


RSI 止损 EA 结果

结果
历史品质: 100%
柱线: 20160 即时报价: 603385 品种: 1
总净盈利: 327.71 余额绝对回撤: 288.96 净值绝对回撤: 367.85
毛盈利: 3 525.74 余额最大回撤: 483.90 (69.63%) 净值最大回撤: 523.24 (71.95%)
毛利亏损: -3 198.03 余额相对回撤: 69.63% (483.90) 净值相对回撤: 73.65% (369.45)
盈利因子: 1.10 预期收益: 1.76 保证金等级: 317.21%
恢复因子: 0.63 锋锐比率: 0.08 Z-得分: 1.68 (90.70%)
AHPR: 1.0070 (0.70%) LR 相关性: 0.51 OnTester 结果: 0
GHPR: 1.0027 (0.27%) LR 标准误差: 134.83
总交易: 186 做空交易 (胜率 %): 94 (42.55%) 做多交易 (交易 %): 92 (38.04%)
总成交: 372 盈利交易 (% 总交易): 75 (40.32%) 亏损交易 (% 交易): 111 (59.68%)
最大盈利交易: 85.26 最大亏损交易: -264.99
平均盈利交易: 47.01 平均亏损交易: -28.81
最大连续获胜 ($): 5 (350.60) 最大连续亏损 ($): 6 (-255.81)
最大连续盈利 (计数): 350.60 (5) 最大连续亏损 (计数): -413.34 (5)
平均连续获胜: 2 平均连续亏损: 2

rsistlEcurve

图例 3.4 RSI 止损 EA 的净值曲线

经典止损 EA 结果


结果
历史品质: 100%
柱线: 20160 即时报价: 603385 品种: 1
总净盈利: 3 672.06 余额绝对回撤: 215.45 净值绝对回撤: 217.30
毛盈利: 10 635.21 余额最大回撤: 829.54 (19.27%) 净值最大回撤: 1 159.20 (25.59%)
毛利亏损: -6 963.15 余额相对回撤: 48.76% (270.82) 净值相对回撤: 51.81% (303.90)
盈利因子: 1.53 预期收益: 15.97 保证金等级: 274.21%
恢复因子: 3.17 锋锐比率: 0.16 Z-得分: -0.14 (11.13%)
AHPR: 1.0120 (1.20%) LR 相关性: 0.80 OnTester 结果: 0
GHPR: 1.0093 (0.93%) LR 标准误差: 545.00
总交易: 230 做空交易 (胜率 %): 107 (44.86%) 做多交易 (交易 %): 123 (38.21%)
总成交: 460 盈利交易 (% 总交易): 95 (41.30%) 亏损交易 (% 交易): 135 (58.70%)
最大盈利交易: 392.11 最大亏损交易: -219.95
平均盈利交易: 111.95 平均亏损交易: -51.58
最大连续获胜 ($): 6 (1 134.53) 最大连续亏损 ($): 9 (-211.43)
最大连续盈利 (计数): 1 134.53 (6) 最大连续亏损 (计数): -809.21 (4)
平均连续获胜: 2 平均连续亏损: 2


classicalcure

图例 3.5. 经典止损 EA 的净值曲线


观察

尽管两个 EA 在交易期结束时都是盈利的,但据观察,第一个 EA(RSI 止损 EA)的亏损更少,而其中有些巨额亏损。

RSI 止损的净值曲线亏损分析

图例 3.6. 净值曲线亏损

这些亏损可能会影响 EA 的整体盈利能力,以及相应的资金管理。 另一方面,经典的止损 EA 亏损更多,但在交易期结束时也赚取了很多的金钱。


结论和建议

资金管理的确是交易的圣杯。 从上面的实验来看,全面实现资金管理的 EA 盈利更多,亏损也更多。 这是因为交易的一致性。 然而,由于风险程度的不同,依据 RSI 定义止损并不能完全得到与第一个 EA(RSI 止损)相同的一致性。

建议

在第一个(RSI 止损)EA 中,对冲是降低亏损的途径之一。 这也许会带来更一致的风险程度,并改善长期盈利能力。


感谢您的阅读!!!

本文由MetaQuotes Ltd译自英文
原文地址: https://www.mql5.com/en/articles/9827

附加的文件 |
DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能 DoEasy 函数库中的图形(第八十九部分):标准图形对象编程。 基本功能
目前,该函数库能够跟踪客户端终端图表上的标准图形对象,包括删除和修改其某些参数。 在当下,它还缺乏从自定义程序创建标准图形对象的能力。
针对交易的组合数学和概率论(第五部分):曲线分析 针对交易的组合数学和概率论(第五部分):曲线分析
在本文中,我决定进行一项研究,探讨将多重状态系统简化为双重状态系统的可能性。 本文的主要目的是分析并推导出有用的结论,这些结论也许有助于基于概率论的可伸缩交易算法的深入发展。 当然,这个话题会涉及到数学知识。 不过,根据之前文章的经验,我认为广谱信息比细节作用更大。
在 MQL5 中使用 AutoIt 在 MQL5 中使用 AutoIt
简述。 在本文中,我们将探索采用 MetraTrader 5 终端里以集成的 MQL5 编写 AutoIt 脚本。 在其中,我们将覆盖如何操纵终端的用户界面来自动完成各种任务,并介绍一个采用 AutoItX 库的类。
针对交易的组合数学和概率论(第四部分):伯努利(Bernoulli)逻辑 针对交易的组合数学和概率论(第四部分):伯努利(Bernoulli)逻辑
在本文中,我决定重点阐述著名的伯努利(Bernoulli)规划案,并展示如何用它来描述与交易相关的数据数组。 所有这些将被用来创建一个自适应的交易系统。 我们还将寻找一个更通用的算法,一个特例是伯努利公式,并查找能够运用它的应用。