请 [注册] 或 [登录]  | 返回主站

量化交易吧 /  量化策略 帖子:3365983 新帖:4

解读经典与隐性背离的新途径

汇市江湖百晓生发表于:4 月 17 日 15:13回复(1)

概述

交易者经常使用经典的技术分析方法。然而, 有许多不同的方式和方法, 也是有用的。在本文中, 我提出了一个搜索和解读背离的非标准方法。基于这种方法, 我们将创建一个交易策略。

定义背离/趋合

只要市场的参与者有意愿和资金进行交易, 行情的走势就会长期持续下去。所以, 当所有参与者都已入市, 迟早会有一刻到来, 没有人可以推动价格了。这种情形也许在市场上会经常发生。根据趋势方向, 它们被称为市场超买或超卖状态。

超买状态 也许会发生在金融, 股票或期货市场。这表明那些想要购买资产的人已经买入了, 从而没有人去推高价格了。

超卖状态 是相反的情形。这表明那些想抛售资产的人已经卖掉了, 因而没有人去拉低价格了。

超买/超卖状态不会随处出现。众所周知, 价格以波浪的形式运动。交易者通过比较价格图表与指标或振荡器图表来跟踪价格变化。当指标行为与价格走势方向不同时, 在看跌市场形成 趋合, 在看涨市场形成 背离

背离的类型

不同的研究者提出了不同的行情背离/趋合分类。我们所用的是将背离/趋合划分为经典和隐性。

经典背离

经典背离可通过比较新高点/新低点与同一时刻的指标图表上的数值来确定。如果价格图表形成又一个新高点或低点, 而指标走势图表下跌, 则是一个背离的迹象。若行情处于超买(超卖), 则在当前的趋势方向上开单是不可取的。

经典背离在各种资料中被广泛描述。依据发散特征, 可将其划分为三个小类

  • A 类。它比其它类更经常发生。当资产价格创新高/新低时, 指标开始反转, 这意味着背离, 以及可能的即将到来的逆转。
  • B 类。类似于 A 类, 只是资产价格未能突破极值, 形成双顶双底反转形态, 且指标没有达到极值。
  • C 类。价格新高或新低, 指标形成双顶 (双底) 模式。

背离(趋合) 可以连续重现若干次, 组合不同的类别, 从而创建一个更强的反转模型。每一类别都应分别进行分析。我们不能断言哪一个是最强的, 亦或最弱的。我们稍后会分析原因。

隐性背离

这种背离也可以划分为几个小类:

  • 价格高点逐次降低, 而振荡器伴随着走高, 这可确认下行趋势。
  • 价格低点逐次抬高, 而振荡器伴随着走低, 这可确认上行趋势。


在上图中, 我们可以清楚地看到上涨行情, 但 MACD 已经形成了新的低点, 而这并没有被价格图表所证实。这一矛盾暗示存在一个隐性的看涨背离, 表明上升趋势增强。

用于发现背离/趋合的指标和振荡器。它是如何运作的

哪些指标可以显示背离和趋合?一个技术指标应该能够判断需求和供应级别, 并跟踪动量。以下指标可用于上述目的: 振荡器, 随机指标, RSI, CCI 等, 以及含有振荡器元素 MACD 的趋势指标。MACD 可以解释为多条移动均线的发散和收敛。该指标有效地跟踪价格变动和动量的差异。许多交易者基于 MACD 的收敛/发散进行决策。

不过, 推荐上述任何工具来处理背离都是错误的。每位交易者都应该选择一个适合他们特定交易策略的指标, 能够高效地工作且不会令价格图表超载。因此, 一般建议如下: 检查指标清单, 对其进行测试, 选择其中的一个, 根据其信号交易, 不关注其它因素。

另外, 无需指标也可以轻易地判定背离。首先, 您应该了解背离形成的基础。

动量在背离的形成中起着重要的作用。我们知道强爆发后走势动量幅度的降低是背离形成的信号。


上图显示了这个例子。当形成一个新低点时, 新波浪的尺度小于前一个。在这种情况下, 我们能够期待一个新的背离。

下例显示相同行情部分的 RSI 指标, 证实了上述假设。


虽然背离很容易就可判定, 但这种方法在未使用指标的情况下是不完整的。我们没有看到趋合/发散指示线。所以, 我们来研究几个识别这种形态的最常用指标。

RSI 振荡器

RSI 振荡器特区域 >-100 和 <+100, 分别代表超卖区和超买区。所有出现在这些区域内的信号被认为是强烈的, 且背离信号被认为更强烈。

这种方法的缺点其实在于指标对价格波动非常敏感。这令该指标用来识别波峰和波谷变得十分困难。价格图表需要进行分析。这导致信号检测的延迟。

Stochastic 振荡器

以下用于振荡器的标准参数:

  • %K 周期: 5
  • %D 周期: 3
  • 慢速: 3

类似于 RSI, Stochastic 振荡器也有超买区和超卖区。这些区域的背离或趋合显著增加了有利交易成果的机会。

Stochastic 指标的缺点是背离出现过多, 即大量的假信号。所有信号都应解读为可能变化的预警, 因此有必要使用额外的技术来检测入场点。

MACD 振荡器

MACD 是一个有趣的振荡器, 也可以帮助检测背离。以标准参数使用该指标:

  • 快速 EMA: 12
  • 慢速 EMA: 26
  • MACD SMA: 9


运用 MACD 判定背离的规则之一如下: 振荡器柱线不得与零轴交叉。下面的截图显示, 在这种情况下, 背离并不明显, 因此盈利交易的机会很低。

不像以前的指标, 这一个产生的信号更少。但这是一个趋势指标, 因此它会通告行情的全局变化。尽管拥有许多优点, 入场仍需通过价格行为分析或烛条形态来确认。

交易量指标

交易量是另一个重要特征。价格和交易量的背离 (或趋合) 是最强烈的反转信号之一。思路如下:

只要有新的交易量涌入市场, 价格就会继续上涨。在高位突破之一, 我们看到成交量下降, 这意味着买家停止向市场提供资金。我们可以得出这样的结论, 价格超买, 并有可能向下。所描述的情况如下图所示。

在这种情况下, 我认为 OBV 是最有趣的指标。它基于这种隐性背离提供了良好的入场信号。

对于 OBV 的经典背离, 往往只表示放缓并向稳固过渡。


确定背离/趋合的规则。如何进行背离交易

我们来讨论一下交易者尝试发现趋合/背离, 并根据这种形态进行交易时常犯的错误。

  • 趋势的存在是强制性的; 背离不会在横盘时产生。
  • 除了背离之外, 您还应该使用价格行为或日本烛条来确认入场。
  • 不要指望您已发现了 100% 的信号。总会有出错的可能性。所以, 在进行交易操作时, 应遵守常规的交易规则。
  • 使用新闻指标构建的蜡烛条不能用来检测背离。由于新闻发布期间波动较大, 烛条往往会产生假信号。
  • 背离必须明确。您必须确保信号不仅对您, 而且也对其它市场参与者可见。决策正确机会也许只在这种情况下增加。
  • 只分析最近的波峰和波谷。这可更清晰地理解这种情形。在使用诸如 MACD 等趋势指标时, 零轴的交叉点可能会削弱信号甚至取消信号。

一种新方法

我们已经研究了使用和建立背离形态的常用规则。现在我们将观看交易中使用的非标准背离。在我们的操作中, 我们不会使用标准规则, 而是会使用另外一个绝对非典型的指标。

我们将在 比尔·威廉姆斯 的经典 加速器振荡指标 的基础上进行实验。这个选择并非偶然。指标方向改变先于驱动力变化之前, 而驱动力方向在价格变化之前改变。AO 是早期的确认信号, 具有明显的优势。我们可以更早, 更频繁地接收到背离信号。正常时这种解决方案会导致噪声增加, 但在我们的情况下, 我们有更多的入场信号和更早的减速信号。

我们已经研究了使用和构建背离的常用规则。这种背离使用的变体是非标准的。我们仍然遵循这些常用规则, 同时使用非正常方式确定入场点。

这个工具的主要目的是发现背离, 所以它的变量将只包含一个参数 — 用于判断背离的柱线数量。

#property indicator_separate_window
//---- 用于指标计算和绘制的一个缓冲区
#property indicator_buffers 2
//---- 只使用一个图形构造
#property indicator_plots 1
//---- 指标绘制为一条线
#property indicator_type1 DRAW_COLOR_HISTOGRAM
//---- 指标线使用蓝色
#property indicator_color1 Green,Red
//----
#property indicator_width1 2
//---- 指标线是连续的曲线
#property indicator_style1 STYLE_SOLID
//---- 显示指标标签
#property indicator_label1 "AC_Div"
//+------------------------------------------------------------------+
input int Bars_Calculated=1000;
//+------------------------------------------------------------------+
string shortname="";
double AC_buff[];
double Color_buff[];
int wid;
int Handle_AC;
//---
#define DATA_LIMIT 37

指标用多色直方图的预设参数初始化。

//+------------------------------------------------------------------+
//| 自定义指标初始化函数                                                 |
//+------------------------------------------------------------------+
int OnInit()
 {
//---- 设置动态数组作为指标缓冲区
 SetIndexBuffer(0,AC_buff,INDICATOR_DATA);
 SetIndexBuffer(1,Color_buff,INDICATOR_COLOR_INDEX);
//---- 设置指标绘图开始位置
 PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,DATA_LIMIT);
//---- 初始化指标简称的变量
 shortname="Accelerator_Divergence";
//---- 创建在单独子窗口和工具提示中显示的名称
 IndicatorSetString(INDICATOR_SHORTNAME,shortname);
//---- 定义指标值的显示精度
 IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//---- 禁用绘制空指标值
 PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
 PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, 0.0);
//--- 加速器指标的句柄
 Handle_AC=iAC(NULL,0);
//--- 查找图表子窗口的索引
 wid=ChartWindowFind(0,shortname);
//---
 return(INIT_SUCCEEDED);
 }

主要指标计算代码由两部分组成。

第一部分是基本指标。

//---- 声明局部变量 
 int limit,bar,pos;
//---- 检查柱线数量是否足够进行计算
 if(rates_total<DATA_LIMIT)
 return(0);
 int barsCalculated=MathMin(Bars_Calculated,rates_total);
//+------- 设置数组索引方向 ---------------------+
 ArraySetAsSeries(close,true);
 ArraySetAsSeries(AC_buff,true);
 ArraySetAsSeries(low,true);
 ArraySetAsSeries(high,true);
 ArraySetAsSeries(Color_buff,true);
 ArraySetAsSeries(time,true);
//+--- 确定计算所需的柱线数量 --------+
 limit=rates_total-DATA_LIMIT-1;
 if(prev_calculated>0) limit=rates_total-prev_calculated;
 pos=limit;
 if(pos>barsCalculated)pos=limit;
 int to_copy;
 if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total;
 else
 {
 to_copy=rates_total-prev_calculated;
 if(prev_calculated>0) to_copy++;
 }
//---
 if(IsStopped()) return(0); //Checking for stop flag
//+----- 主要数组 -------------------------------------+
 if(CopyBuffer(Handle_AC,0,0,to_copy,AC_buff)<=0)
 {
 Print("getting Accelerator Handle is failed! Error",GetLastError());
 return(0);
 }
//+---------- 直方图着色 --------------------------------+
 for(bar=limit; bar>=0 && !IsStopped(); bar--)
 {
 Color_buff[bar]=0.0;
 if(AC_buff[bar]<AC_buff[bar+1])Color_buff[bar] =1.0;
 if(AC_buff[bar]>AC_buff[bar+1])Color_buff[bar] =0.0;
 }

第二部分包括搜索背离。

//+----------- 检测向上背离 ------------------------------+
 int bars=barsCalculated;
 for(bar=pos; bar>=0 && !IsStopped(); bar--)
 {
 int l=bar+2;
 if(Extremum(AC_buff[l+1],AC_buff[l],AC_buff[l-1])<0)
 {
 int i=l;
 int counted=LastPeak(l,bars,AC_buff);
 if(counted!=-1)
 {
 if(AC_buff[i]<AC_buff[counted] && high[i]>high[counted])
 {
 DrawPriceTrendLine(time[i],time[counted],high[i],high[counted],Red,STYLE_SOLID);
 DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Red,STYLE_SOLID);
 }

 if(AC_buff[i]>AC_buff[counted] && high[i]<high[counted])
 {
 DrawPriceTrendLine(time[i],time[counted],high[i],high[counted],Red,STYLE_DOT);
 DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Red,STYLE_DOT);
 }
 }
 }
//+----------- 检测向下背离 ------------------------------+
 if(Extremum(AC_buff[l+1],AC_buff[l],AC_buff[l-1])>0)
 {
 int i=l;
 int counted=LastTrough(l,bars,AC_buff);
 if(counted!=-1)
 {
 if(AC_buff[i]>AC_buff[counted] && low[i]<low[counted])
 {
 DrawPriceTrendLine(time[i],time[counted],low[i],low[counted],Green,STYLE_SOLID);
 DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Green,STYLE_SOLID);
 }
 if(AC_buff[i]<AC_buff[counted] && low[i]>low[counted])
 {
 DrawPriceTrendLine(time[i],time[counted],low[i],low[counted],Green,STYLE_DOT);
 DrawIndicatorTrendLine(time[i],time[counted],AC_buff[i],AC_buff[counted],Green,STYLE_DOT);
 }
 }
 }
 }

为了减少代码量, 单独提供图形化结构和高点/低点搜索函数。

//+----- 搜索第二个向上极值 --------------------------+
int LastPeak(int l,int bar,double &buf[]) 
 {
 for(int i=l+5; i<bar-2; i++)
 if(Extremum(buf[i+1],buf[i],buf[i-1])<0)return (i);
 return (-1);
 }
//+----- 搜索第二个向下极值 --------------------------+
int LastTrough(int l,int bar,double &buf[])
 {
 for(int i=l+5; i<bar-2; i++)
 if(Extremum(buf[i+1],buf[i],buf[i-1])> 0)return (i);
 return (-1);
 }
//+-- 搜索极值 -------------------------------------------+
int Extremum(double a,double b,double c)
 {
 if((a-b)*(b-c)<0)
 {
 if(c>b && b<0) return(1); //DN extremum
 if(c<b && b>0) return(-1);//UP extremum
 }
 return(0);
 }
//+------ 在价格图表上创建对象 -----------------------+
void DrawPriceTrendLine(datetime T_0,
 datetime T_1,
 double P_0,
 double P_1,
 color color_0,
 int style)
 {
 string name_2=shortname+DoubleToString(T_0,0);
 string name_0;
 name_0=shortname+"Line_Sn"+ColorToString(color_0);
//--- 
 if(ObjectFind(0,name_2)<0)
 drawLineS(name_2,T_0,T_1,P_0,P_1,color_0,style,0,true,false,0);
//+-----------+
 if(style==STYLE_DOT)
 drawLineS(name_0,T_1,T_0,P_1,P_0,clrAqua,0,3,true,true,0);
 }
//+------ 在指标窗口中创建对象 ------------------+
void DrawIndicatorTrendLine(datetime T_0,
 datetime T_1,
 double P_0,
 double P_1,
 color color_0,
 int style)
 {
 string name_1,name_0;
 int window= wid;
 name_1 = shortname+DoubleToString(T_0+wid,0);
 if(ObjectFind(0,name_1)<0)
 drawLineS(name_1,T_0,T_1,P_0,P_1,color_0,style,0,false,false,window);
//---
 if(style==STYLE_SOLID)
 {
 name_0=shortname+"Line_Pn"+ColorToString(color_0);
 drawLineS(name_0,T_1,T_0,P_1,P_0,clrMagenta,style,2,true,true,window);
 }
 }
//+------------------------------------------------------------------+
void drawLineS(string name,
 datetime t0,
 datetime t1,
 double p0,
 double p1,
 color clr,
 int style,
 int width,
 bool back,
 bool ray,
 int window)
 {
 ObjectDelete(0,name);
 ObjectCreate(0,name,OBJ_TREND,window,t0,p0,t1,p1,0,0);
 ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,ray);
 ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
 ObjectSetInteger(0,name,OBJPROP_STYLE,style);
 ObjectSetInteger(0,name,OBJPROP_WIDTH,width);
 ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
 ObjectSetInteger(0,name,OBJPROP_BACK,back);
 }
//+------------------------------------------------------------------+


为了便于直观分析, 我们用实线表示经典背离, 用虚线表示隐性背离。红色用于看跌背离, 绿色用于看涨背离。粗线显示价格图表上的最后隐性看涨和看跌背离, 以及指标窗内的经典背离。我会进一步解释这些可视化规则。指标看起来像这样:

策略的基本原则

价格图表和指标的分析表明, 价格图表上逆转背离的延长线和指标图表上经典背离的延长线成为倾斜的支撑和阻力位。有力突破这些线表征了进一步的短线/长线的市场行为。

位于价格图表上突破由隐性背离形成的支撑线的例子:


在下个例子中, 直方图柱线突破了指标窗口中的经典背离指示线:

突破之后, 指示线的角色常常改变。即, 被突破的支撑位变成了阻力位:

我们将根据这些行为特征制定策略。


交易原则

您可以用挂单和市价单两者进行交易。时间帧和交易时间并不重要。主要原则是指示线的突破确定。在进行挂单交易时, 我们把它们放置于正在突破的烛条或直方图上正成形柱状的最高价 (最低价) 处。烛条应在突破方向。换言之, 如果指示线向上突破, 烛条应将阳线收盘, 反之亦然。 

下图显示价格图表, 其中隐性背离有可能被突破: 有一个开多仓的信号, 随后被确认。在指标窗口中, 经典背离指示线被突破, 所以有一个开空单的信号, 但随后这个信号未能被确认。


下图显示了另一种情况: 当指标窗口中的经典背离指示线被突破时形成买入信号。信号稍后被确认。

下面是另一个有趣的例子。两个信号同时出现在一根烛条上: 一个买入信号和一个卖出信号。在这种情况下, 我们可以检查振荡器的值。但即使我们忽略振荡器, 我们也会看到只有所需的订单被触发, 所以卖出交易被确认。此外, 还有另一个卖出信号, 这为前者增强。它允许增加交易量, 从而增加利润。


一个经典的卖出信号:

下图显示了卖出信号 (后来被振荡器取消) 和两个买入信号。


止损设定在最近的局部极值以下。止盈设在支撑/阻力位。在反趋势交易期间, 支撑/阻力位可以在我们的指示线上设定。但在这种情况下要小心, 因为市场形势可能发生巨大变化, 您可能需要调整止盈价位。

在较低的时间帧 (М1-М15), 价格通常在突破之后回到指示线, 形成 1-2-3 的形态,, 加强信号。所以, 如果市场不够活跃, 最好等到价格突破烛条高点或低点后再入场。当然, 背离的经典解释也是有效的。尽管振荡器并不像其它策略那样重要, 主要用于图形化构造, 但仍建议在交易时参考振荡器行为。AO 指标用于广泛的各种策略。AO 和所描述方法的组合可以显著提高这种策略的有效性。

为了测试我们策略的可行性, 我们来创建一个使用挂单交易的智能交易系统。主要的问题在于我们不能简单地在智能交易系统中调用指标。在这种情况下, 指标不会在指标窗口中绘制任何东西。由于我们需要图形化构造, 所以我们将指标的代码部分插入到 EA 代码中。

input double InpLots =0.1;           // 手数
input int InpTakeProfit =150;        // 止盈 (点值)
input int InpStopLoss =60;           // 止损 (点值)
input int InpTrailingStop =25;       // 尾随停止价位 (点值)
input int InpOffset =5;              // 自价格距离 (点值)
input int InpDellOorder =30;         // 订单删除距离 (点值)
//---
int ExtTimeOut=10;                   // 交易操作之间的间隔时间
int barsCalculated=1000;
datetime t=0;
datetime time[];


除了手 Lots, TakeProfit, StopLoss 和 TrailingStop 等传统变量之外, 我们还增加了Offset 和 DellOorder。第一个设置突破烛条的高点或低点与订单之间的距离 (点值)。如果订单尚未触发, 并且价格在 DellOorder (点值) 距离处反方向移动, 则应删除订单。

这个智能交易系统不是原创的, 所以我们只讨论要点。我们不会使用交易过滤器, 但我们会稍微修改原始代码。

//+------------------------------------------------------------------+
//| 基本计算                                                          |
//+------------------------------------------------------------------+
 for(int bar=1; bar>0 && !IsStopped() && t!=time[0]; bar--)
 {
 int l=bar+1;
 int p1=0,p2=0;
 //+----------- 检测向上背离 ------------------------------+
 if(Extremum(m_buff_ind[l+1],m_buff_ind[l],m_buff_ind[l-1])<0)
 {
 int i=l;
 int counted=LastPeak(l,bars,m_buff_ind);
 if(counted!=-1)
 {
 if(m_buff_ind[i]<m_buff_ind[counted] && high[i]>high[counted] && !d1)
 { drawLine("Buy_1",time[i],time[counted],m_buff_ind[i],m_buff_ind[counted],Red,1); d1=true;}
 //---
 if(m_buff_ind[i]>m_buff_ind[counted] && high[i]<high[counted] && !d2)
 {
 p1=ArrayMaximum(high,i-1,5);p2=ArrayMaximum(high,counted-2,5);
 drawLine("Buy_2",time[p1],time[p2],high[p1],high[p2],Red,0);d2=true;
 }
 }
 }
 //+----------- 检测向下背离 ------------------------------+
 if(Extremum(m_buff_ind[l+1],m_buff_ind[l],m_buff_ind[l-1])>0)
 {
 int i=l;
 int counted=LastTrough(l,bars,m_buff_ind);
 if(counted!=-1)
 {
 if(m_buff_ind[i]>m_buff_ind[counted] && low[i]<low[counted] && !d3)
 { drawLine("Sell_1",time[i],time[counted],m_buff_ind[i],m_buff_ind[counted],Green,1);d3=true;}
 //---
 if(m_buff_ind[i]<m_buff_ind[counted] && low[i]>low[counted] && !d4)
 {
 p1=ArrayMinimum(low,i-1,5);p2=ArrayMinimum(low,counted-2,5);
 drawLine("Sell_2",time[p1],time[p2],low[p1],low[p2],Green,0);d4=true;
 }
 }
 }
 if(d1 && d2 && d3 && d4)break;
 t=time[0];
 }
//---
 }

我们知道指标的极值不一定是价格图表上的极值。所以, 为了纠正我们图表上的相关失真, 我们添加了两个函数 ArrayMinimum 和 ArrayMaximum (高亮)。这些函数允许在指标极值形成的价格图表上标识高点和低点。此外, 为了消除零轴附近的微小波动和相应的假信号, 我们修改了判断最高价/最低价的公式。现在只参考具有共同潜力的指标值 (正值或负值)。

//+-- 搜索极值 -------------------------------------------+
int Extremum(double a,double b,double c)
 {
 if(((a-b)*(b-c)<0) && ((a>0 && b>0 && c>0) || (a<0 && b<0 && c<0)))
 {
 if(c>b && b<0) return(1); //DN extremum
 if(c<b && b>0) return(-1);//UP extremum
 }
 return(0);
 }
//+------

我们还使用 ObjectGetValueByTime 函数来判断某个时间坐标处的指示线数值。这个函数被多次使用。出于便利起见, 将分开添加。

//+------------------------------------------------------------------+
//|返回指定对象指定时间处的价格数值                                        |
//+------------------------------------------------------------------+
double CSampleExpert::ValueByTime(string label,int i)
 {
 double p=0.0;
//---
 p=ObjectGetValueByTime(0,label,time[i],0);
 return(p);
 }
//+------------------------------------------------------------------+

正如我们已经提到的, 我们不会使用交易过滤器。我们不打算创建一个全功能的交易机器人, 我们只想评估策略的有效性。所以信号模块非常简单。我们判断这条指示线是否在期望的方向上突破, 以及价格 (指标) 方向当前朝何处移动。

//+------------------------------------------------------------------+
//| 检查开空单的条件                                                    |
//+------------------------------------------------------------------+
bool CSampleExpert::ShortOpened(void)
 {
 bool res=false;
//---
 double pp1=EMPTY_VALUE,pp2=EMPTY_VALUE,pp3=EMPTY_VALUE,
 pp4=EMPTY_VALUE,pp5=EMPTY_VALUE,pp6=EMPTY_VALUE;
//---
 if(ObjectFind(0,"Sell_2")!=-1)
 {
 pp1=ValueByTime("Sell_2",1);
 pp2=ValueByTime("Sell_2",2);
 pp3=ValueByTime("Sell_2",3);
 }
 if(ObjectFind(0,"Sell_1")!=-1)
 {
 pp4=ValueByTime("Sell_1",1);
 pp5=ValueByTime("Sell_1",2);
 pp6=ValueByTime("Sell_1",3);
 }
//--- 检查空头仓位的可能性 (卖出) 
 if((pp1!=EMPTY_VALUE && close[1]<pp1 && close[2]>pp2&&close[0]<close[1])||
 (pp4!=EMPTY_VALUE && m_ind_1>m_ind_0 && ((m_ind_1<pp4 && m_ind_2>pp5) ||(m_ind_2<pp5 && m_ind_3>pp6))))
 {
 //--- 任何情况下, 我们都需要退出智能交易系统
 res=true;
 }
//--- 结果
 return(res);
 }
//+------------------------------------------------------------------+


以上部分展示了空头仓位入场的模块。多头入场与此类似。

在收到信号 (指示线突破) 之后, 我们在所突破烛条附近的高点或低点距离 InpOffset 处设置一笔合适的订单。如果该烛条是突破烛条, 则订单将直接放置在该烛条上。 

//+------------------------------------------------------------------+
//| 开一笔向下突破卖出单                                                 |
//+------------------------------------------------------------------+
bool CSampleExpert::OpenSellStop(void)
 {
 bool res=false;
//--- 搜索最近烛条中的最低柱线
 int i=ArrayMinimum(low,0,3);
//---
 if(ShortOpened())
 {
 double offset=InpOffset;                          // 距烛台低点放置订单的距离点值
 double limit_price=m_symbol.Bid();
 double price=low[i]-offset*m_adjusted_point;;
 double tp =price-m_take_profit;
 double sl =price+m_stop_losse;
 //--- check the account balance
 if(m_account.FreeMarginCheck(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,price)<0.0)
 printf("资金不足。可用保证金 = %f",m_account.FreeMargin());
 else
 {
 //--- 开仓
 if(m_trade.OrderOpen(Symbol(),ORDER_TYPE_SELL_STOP,InpLots,limit_price,price,sl,tp))
 {res=true; printf("已开仓品种 %s",Symbol());}
 else
 {
 printf("SELL STOP %s 开仓错误: '%s'",Symbol(),m_trade.ResultComment());
 printf("开仓参数: 价格=%f, 止盈=%f",price,tp);
 }
 }
 }
//--- 结果
 return(res);
 }
//+------------------------------------------------------------------+

如果订单未能触发, 并且价格在相反方向上移动的距离大于 InpDellOorder, 那么订单应该被删除。

//+------------------------------------------------------------------+
//| 删除不必要的订单                                                    |
//+------------------------------------------------------------------+
bool CSampleExpert::DelOrder(ulong ticket,string type)
 {
 bool res=false;
 if(m_trade.OrderDelete(ticket))
 printf("已开仓品种 %s",Symbol());
 else
 {
 res=true;// 设置标志, 表示订单尚未被删除
 printf("删除订单错误"+type+" %s : '%s'",Symbol(),m_trade.ResultComment());
 }
 return(res);
 }
//+------------------------------------------------------------------+

我们回到我们的主要目标, 即针对策略的评估。评估依照图形构造操作的策略, 其难度在于只能在可视模式中进行评估。自动模式下的优化是不可能的。这是一个耗时的过程。所以, 我们选取 GBPUSD H1, 从 2017 年初开始运行智能交易系统。我们使用默认设置。

此为结果:




这种方法很难称之为完全客观。不过, 所获得的结果显示该策略具有良好的潜力。从长远来看, 经过进一步的改善, 可以变成有价值的策略。


结束语

这种方法令我们能够创建一个完全可行的策略, 且允许使用其它工具。这种策略的缺点包括: 偶尔错误地构建指标线, 且需要手工纠正。这令该策略难以自动化, 且其结果因此难以分析。无论如何, 研究表明, 不仅经典战略可以存在。

本文中使用的程序:

#名称类型 描述 
1Accelerator_Div指标

指标 基于加速器指标来判断显性的和隐性的背离/趋合

2TestExpert智能交易系统

用于策略测试的智能交易系统

全部回复

0/140

达人推荐

量化课程

    移动端课程