English Русский Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
学习如何基于 OBV 设计交易系统

学习如何基于 OBV 设计交易系统

MetaTrader 5交易 | 12 八月 2022, 10:36
1 692 0
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

概述

在这篇新文章中,我们将学习一个新的技术指标,它可以处理成交量,并帮助我们从不同的角度看待问题:我们将详细讨论能量潮(OBV)指标,尝试涵盖这一有趣的话题,并学习如何利用这一技术指标来令我们受益。 以下是该指标将涵盖的主题:

  1. OBV 定义
  2. OBV 策略
  3. OBV 策略蓝图
  4. OBV 交易系统
  5. 结束语

贯穿 OBV 定义主题,我们将详细了解 OBV 指标:我们将辨别它是什么、如何测量、以及如何计算、并查看其计算示例。 之后,我们能够深入辨别和了解该指标,从而掌握如何正确使用该指标。 我们将学习如何使用 OBV 指标,以及基于该指标概念的简单策略 — 这将贯穿 OBV 策略主题。 在我们辨别如何基于简单策略运用它之后,我们将为简单策略设计蓝图,这将有助于我们编写这些策略的 MQL5 代码,因为该蓝图能帮助我们安排和组织创建智能交易系统的步骤。 在设计策略蓝图之后,我们将准备用 MQL5 编写代码,创建一个智能交易系统,并在 MetaTrader 5 中运行它,还可自动或通过手工操作来确地执行我们的交易策略。

我需要提醒的是,在本文中,我们将使用 MQL5(MetaQuotes 语言)编写和创建我们的智能系统。 然后我们将在 MetaTrader 5 交易平台上执行它们。 如果您打算了解更多关于如何安装 MetaTrader 5 的信息,以便能够使用 MetaTrader 5 内置的 MQL5,您可以查看我上一篇文章中关于在 MetaEditor 中编写 MQL5 代码的主题。 若您想掌握所学知识,我建议您自己应用所读的内容,因为练习是掌握任何东西的重要工具。

免责声明:所有信息“按原样”提供仅用于教学目的,并非出于交易目的或建议。 这些信息不能保证任何结果。 如果您选择在您的任何交易账户上使用这些材料,您将自行承担风险,您是唯一的责任人。

现在,我们来深入阅读本文,学习一种新工具,并将其添加到我们的工具包中,从而增强交易体验。


OBV 定义

在这一部分中,我们将更详尽地了解能量潮(OBV)指标。 但我们首先谈到的是交易量,因为这个指标是交易量指标之一。 因此,成交量是指在特定时间段内参与交易的股权或合约数量。 当我们看到成交量很高时,意味着一种金融产品的交易很活跃,反之亦然,如果我们看到成交量低迷,则意味着该金融产品的交易不活跃。

交易量概念非常重要,因为如果有一种金融产品的走势向上或向下,同时伴随着巨大交易量,则代表它将比伴随着低迷交易量的金融产品更强。 当我们处于上升趋势时,交易量必须随趋势移动,最好能看到交易量随着走势上扬而增加,随着走势向下修正而减少,反之亦然。当我们处于下降趋势时,我们可能会发现交易量随行情下行而增加,随着向上修正而减少。

交易量也能确认突破是真的,亦或只是假突破:当突破伴随巨大交易量完成时,这是突破会延续的信号。 

如果趋势和交易量之间的这种关系如我所说的那样持续下去,这就是当前趋势强劲的标志,如果趋势发生变化,这就成为减弱的标志。 如果您不知道趋势是什么,可以阅读上一篇文章中的趋势定义主题。

能量潮(OBV)由约瑟夫·格兰维尔(Joseph Granville)开发的。 它测量正、负两个方向的交易量。 现在我们需要知道如何计算它。 计算步骤如下:

  1. 检查收盘价 - 它是上涨亦或下跌。
  2. 累加前一次 OBV 值之后所有天数的交易量。
  3. 从前一次 OBV 值中减去下跌天数的交易量。
  4. 如果今天的收盘价等于昨天的收盘价,那么今天的 OBV 值将等于昨天的 OBV 值。

我们看看这些步骤的示例,并计算 OBV 指标。 假设我们有以下金融产品的数据:

天数 收盘价 交易量
1 54
2 55 10000
3 60 15000
4 65 20000
5 60 10000
6 55 5000
7 60 7000
8 50 7500
9 48.75 8000
10 49 5000
11 48 6000
12 47.75 7500
13 48 9000
14 47.50 10000
15 48 7000
16 47 7500
17 46 6000
18 44 5000
19 45 15000

若要依据以前的数据计算 OBV 指标:

我们将检查收盘价,并决定其是否高于前一期收盘价。 如果高于前一日收盘价,我们将在其旁边加上“正值”,表示该日为上升趋势。 如果低于前一日收盘价,我们将在其旁边加上“负值”,表示该日为下跌趋势。

OBV calc 1

然后,我们将前一次 OBV 值加上上升天数的正值交易量,并将前一次 OBV 值减去下跌天数的负值交易量。

OBV calc 2

然后,我们现在已计算出 OBV 值,它显示为测量正值和负值交易量的曲线。 幸运的是,我们不需要手工计算该指标,因为您可以在 MetaTrader 5 的内置指标中找到它。 下图显示了如何在图表上插入该指标:

OBV 插入

一旦您选择指标后,以下指标参数窗口将会打开:

OBV insert1

1 - 交易量类型

2 - OBV 曲线颜色。

3 - OBV 曲线线型。

4 - OBV 曲线宽度。

设置所需参数,并单击“确定”后,指标将附着到图表:

OBV 加载


OBV 策略

在本部分中,我们将学习如何根据 OBV 指标的概念运用它。 我们来看一个简单策略。 然而,请注意,这些策略也许并不适合所有人。 因此,任何策略在使用之前您必须对其进行测试,从而了解它与您的契合程度。 在此,我们研究的所有这些策略,主要目的是学习 OBV 指标的基本知识,并了解其工作原理。

  • 策略一: 简单 OBV 走势

根据该策略,我们需要通过比较当前 OBV 值和前一次 OBV 值来判定 OBV 曲线的方向,并查看当前值是否大于前值,这意味着 OBV 正在上升。 反之亦然,如果当前值小于前值,则 OBV 下降。

您可以更改所需的数据长度,将当前 OBV 与更多以前的数据进行比较,但在此,我们只是分享如何使用指标,以及如何以 MQL5 编写代码。 稍后,您可以根据自己的偏好对其进行优化。

当前 OBV > 前一次 OBV --> OBV 正在上升

当前 OBV < 前一次 OBV --> OBV 正在下降

  • 策略二: 简单 OBV 强度

根据该策略,我们需要将当前 OBV 值与前四次 OBV 值的平均值进行比较,来判定其强度。 如果当前 OBV 值大于前四次 OBV 值的平均值,则 OBV 为强,反之亦然;如果当前 OBV 值小于前四次 OBV 值的平均数,则 OBV 为弱。

您也可以增加平均值的长度,将其与当前数据进行比较,但这里的目标是了解如何使用该指标。 然后,您可以根据您的偏好和测试结果调整任何您想要的内容。 

当前 OBV > 前四次 OBV 值的均值 --> OBV 强

当前 OBV < 前四次 OBV 值的均值 --> OBV 弱

  • 策略三: 简单 OBV - 上行趋势

正如我们所知,在上行趋势期间,最好能看到交易量伴随趋势前进。 因此 OBV 应该随着上行走势而增加。 因此,该策略能够评估走势是否强劲。 我们将取当前 OBV 值与上一次 OBV 值进行比较,并比较当前高点和上一个高点。 若当前 OBV 值大于前一次 OBV 值,且当前高点大于前高点时,上行趋势期间走势上移强劲。

当前 OBV > 前一次 OBV,且当前高点 > 前高点 --> 上行趋势中的强劲走势

  • 策略四: 简单 OBV - 下行趋势

在下行趋势中,最好看到交易量伴随趋势变化。 OBV 应伴随下行走势而增加。 这便能够把握走势是否强劲。 我们将取当前 OBV 值与前一次 OBV 值进行比较,并同时比较当前低点和前低点。 若当前 OBV 值小于前一次 OBV 值,且当前低点小于前低点时,下行趋势期间走势下降强劲。

当前 OBV < 前一次 OBV,且当前低点 < 前低点 --> 下行趋势中的强劲走势


OBV 策略蓝图

在这一部分中,我们将为每个策略设计蓝图。 它将提供每一步的清晰描述,讲述如何为每个提到的策略设计一个交易系统。 首先,我们需要设计一个简单的 OBV,在图表上注释里显示当前 OBV 值。 以下是针对它的蓝图:

简单 OBV 蓝图

  • 策略一: 简单 OBV 走势:

在该策略中,我们需要基于当前 OBV 值和前一个 OBV 值来判断 OBV 曲线的方向。 因此,对于每次即时报价,我们需要检查当前 OBV 和前一个 OBV 值,若当前值大于前值时,这将是 OBV 上升的迹象,反之亦然;若当前值小于前值时,这是 OBV 下降的迹象。

以下是该策略每一步的蓝图,可帮助我们为其设计交易系统:

简单 OBV 走势蓝图

  • 策略二: 简单 OBV 强度:

在该策略中,我们需要取当前 OBV 与前四个值的平均值进行比较,从而测量其强度。 如果当前 OBV 大于前四个 OBV 值的平均值,则 OBV 为强,反之亦然;如果当前 OBV 小于前四个 OBV 值的平均数,则 OBV 为弱。

以下是创建该交易系统的每一步蓝图:

简单 OBV 走势蓝图

  • 策略三: 简单 OBV - 上行趋势:

在该策略中,我们需要利用一个交易量指标,即 OBV 来衡量当前的价格走势。 那么好了,在上升趋势期间,我们需要检查当前 OBV 值,并将其与之前一个 OBV 值进行比较,如果当前值大于前值,我们需要检查目前的价格高点,并将它与前价格高点进行比较,如果当前值高于前值,这将是一个在上升趋势中的迹象,且当前上升趋势很强;这是因为我们的当前 OBV 高于前值,且当前高点大于前高点。

以下是针对该策略编码的分步蓝图:

简单 OBV - 上行趋势蓝图

  • 策略四: 简单 OBV - 下行趋势:

在此策略中,若处于下行趋势期间,我们需要检查当前 OBV 值,并将其与之前一个 OBV 值进行比较,如果当前值小于前值,我们需要检查目前的价格低点,并将它与前价格低点进行比较,如果当前值低于前值,这将是一个在下升趋势中的迹象,且当前下行趋势很强;这是因为我们的当前 OBV 低于前值,且当前低点小于前低点。

以下是针对该策略编码的分步蓝图:

简单 OBV - 下行趋势蓝图


OBV 交易系统

在这个有趣的部分中,我们将学习如何为每个提到的策略创建一个交易系统,并以 MQL5 进行编程,因为编程是一个神奇的工具,可以帮助我们轻松创建一个系统来完成以前我们必须手工完成的工作,然而这并非唯一的好处,因为它能准确、快速地执行和完成我们需要的操作,令我们可以从编程中受益匪浅。

现在,我们就要开始为每种策略创建一个交易系统。 首先,我们将创建一个简单 OBV 交易系统,用当前 OBV 值在图表上生成注释。

  • 创建一个 “double” 类型的数组,保存 OBV 值,“double(双精度)”是一种实数或浮点类型,能够以小数部分表示数值。 如您所知,有两种类型的浮点,它们是双精度(double)和浮点(float)。 "double" 类型表示具有两倍浮点(float)类型精度的数字:
double OBVArray[];
  • 调用 “ArraySetaSeries” 函数为 OBV 数设置排序顺序,返回 true(升序)或 false(降序):
ArraySetAsSeries(OBVArray,true);

  • 调用 “iOBV” 函数定义 OBV,并创建整数型变量 OBVDef 保存 “iOBV" 函数返回的能量潮指标的句柄,其参数为(品名、周期、所应用的交易量):
int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);
  • 依据 OBVDef 句柄 调用 “CopyBuffer” 函数,其参数为(指标句柄、缓冲区编号、开始时间、结束时间、缓冲区)来填充 OBVArray,并返回复制数据的数量 :
CopyBuffer(OBVDef,0,0,3,OBVArray);
  • 为 OBV 值创建 double(双精度)变量后,计算当前 OBV 值:
double OBVValue=OBVArray[0];
  • 调用 “Comment” 函数创建注释,并在图表上显示含有当前 OBV 值的注释:
Comment("OBV Value is: ",OBVValue);

如此,以下是先前交易系统的完整代码,该系统以当前 OBV 值显示注释:

//+------------------------------------------------------------------+
//|                                                   Simple OBV.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
void OnTick()
  {
   //creating an array for OBV
   double OBVArray[];
   
   //sorting the array from the current data
   ArraySetAsSeries(OBVArray,true);
   
   //defining OBV
   int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);
   
   //defining EA, buffer, sorting in array
   CopyBuffer(OBVDef,0,0,3,OBVArray);
   
   //calculating current OBV value
   double OBVValue=OBVArray[0];
   
   //creating a comment with OBV value
   Comment("OBV Value is: ",OBVValue);  
  }
//+------------------------------------------------------------------+

此代码编译后,我们就可在 MetaTrader 5 的导航器中找到它,如下所示:

OBV nav1

如果我们想执行它,双击文件或将其拖放到图表上,我们会发现出现如下窗口:

简单 OBV 窗口

按下“确定”后,我们会发现智能系统将加载到图表上,与下图相同:

简单 OBV 加载

然后,我们可从测试中看到生成的信号,与如下示例相同:

简单 OBV 测试信号

如果我们想确保我们得的数值与 Meta Trader 5 内置的能量潮指标值相同,我们可以通过插入能量潮指标来实现这一点;与我们之前提到的一样,在加载我们所创建的智能系统后,我们会发现数值是相同的,下面是一个例子:

简单 OBV 指标信号相同

 现在,我们需要为每个提到的策略创建一个交易系统,下面是如何做到这一点。

  • 策略一: 简单 OBV 走势:

根据这一策略,正如我所提到的,我们需要比较两个值,它们是当前 OBV 值和前 OBV 值,并决定当前值是否大于前值,我们还需要一个信号,该信号显示在图表上的注释里,表示 “OBV is rising”,后随 OBV 当前值和前值。 以下是创建该策略的完整代码:

//+------------------------------------------------------------------+
//|                                          Simple OBV movement.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
void OnTick()
  {
//creating an two arrays for OBV
   double OBVArray1[];
   double OBVArray2[];

//sorting the array from the current data
   ArraySetAsSeries(OBVArray1,true);
   ArraySetAsSeries(OBVArray2,true);

//defining OBV
   int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);

//defining EA, buffer, sorting in array
   CopyBuffer(OBVDef,0,0,3,OBVArray1);
   CopyBuffer(OBVDef,0,0,3,OBVArray2);

//getting the value of current and previous OBV
   double OBVCurrentValue=NormalizeDouble(OBVArray1[0],5);
   double OBVPrevValue=NormalizeDouble(OBVArray2[1],5);

//creating conditions of rising and declining OBV based on its values   
   if(OBVCurrentValue>OBVPrevValue)
     {
      Comment("OBV is rising","\n","OBV current is ",OBVCurrentValue,"\n","OBV previous is ",OBVPrevValue);
     }

   if(OBVCurrentValue<OBVPrevValue)
     {
      Comment("OBV is declining","\n","OBV current is ",OBVCurrentValue,"\n","OBV previous is ",OBVPrevValue);
     }

  }
//+------------------------------------------------------------------+
  • 此代码中的区别:
 为 OBV 创建两个数组:
double OBVArray1[];
double OBVArray2[];

这两个数组的排列顺序均从当前数据开始:

ArraySetAsSeries(OBVArray1,true);
ArraySetAsSeries(OBVArray2,true);

填充这两个数组:

CopyBuffer(OBVDef,0,0,3,OBVArray1);
CopyBuffer(OBVDef,0,0,3,OBVArray2);

调用 “NormalizeDouble” 函数获取 OBV 当前值和前值,该函数返回的双精度型数值匹配 OBVCurrentValue 和 OBVPrevValue 变量预设的精度,“NormalizeDouble” 的参数为(数值,小数位=),其值会填充 OBVArray,小数位 5,即小数点后保留 5 位:

double OBVCurrentValue=NormalizeDouble(OBVArray1[0],5);
double OBVPrevValue=NormalizeDouble(OBVArray2[1],5);

利用 “if 语句设置 OBV 上升和下降的条件:

if(OBVCurrentValue>OBVPrevValue)
   {
    Comment("OBV is rising","\n","OBV current is ",OBVCurrentValue,"\n","OBV previous is ",OBVPrevValue);
   }

if(OBVCurrentValue<OBVPrevValue)
   {
    Comment("OBV is declining","\n","OBV current is ",OBVCurrentValue,"\n","OBV previous is ",OBVPrevValue);
   }

编译后,智能系统将出现在 MetaTrader 5 交易平台的“智能交易系统”文件夹中的导航窗口中,如下所示:

OBV nav2

双击智能系统文件,将出现以下窗口:

简单 OBV 走势窗口

按下“确定”后,智能系统加载到图表,并与下图相同:

简单 OBV 走势加载

以下是根据该策略测试生成信号的示例,

上升 OBV:

简单 OBV 走势上升信号

下降 OBV:

简单 OBV 走势下降信号

  • 策略二: 简单 OBV 强度:

根据这一策略,与我提到的相同,我们需要比较两个数值,即当前 OBV 值和计算出的前四个 OBV 值均值,然后判定当前值是否大于平均值,这意味着 “OBV 正在走强”,反之亦然;如果当前值小于平均值,则意味着 “OBV 正在走弱”。 以下是针对该策略创建交易系统的完整代码:

//+------------------------------------------------------------------+
//|                                          Simple OBV Strength.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
void OnTick()
  {
   //creating an six arrays for OBV
   double OBVArray0[];
   double OBVArray1[];
   double OBVArray2[];
   double OBVArray3[];
   double OBVArray4[];
   
   //sorting arrays from the current data
   ArraySetAsSeries(OBVArray0,true);   
   ArraySetAsSeries(OBVArray1,true);
   ArraySetAsSeries(OBVArray2,true);
   ArraySetAsSeries(OBVArray3,true);
   ArraySetAsSeries(OBVArray4,true);
   
   //defining OBV
   int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);
   
   //defining EA, buffer, sorting in arrays
   CopyBuffer(OBVDef,0,0,5,OBVArray0);
   CopyBuffer(OBVDef,0,0,5,OBVArray1);
   CopyBuffer(OBVDef,0,0,5,OBVArray2);
   CopyBuffer(OBVDef,0,0,5,OBVArray3);
   CopyBuffer(OBVDef,0,0,5,OBVArray4);
   
   //getting the value of current OBV & previous 5 values
   double OBVCurrentValue=NormalizeDouble(OBVArray0[0],5);         
   double OBVPrevValue1=NormalizeDouble(OBVArray1[1],5);
   double OBVPrevValue2=NormalizeDouble(OBVArray2[2],5);
   double OBVPrevValue3=NormalizeDouble(OBVArray3[3],5);
   double OBVPrevValue4=NormalizeDouble(OBVArray4[4],5);
   
   //calculating average of previous OBV value
   double OBVAVG=((OBVPrevValue1+OBVPrevValue2+OBVPrevValue3+OBVPrevValue4)/4);
   
   if(OBVCurrentValue>OBVAVG)
   {
      Comment("OBV is strong","\n","OBV current is ",OBVCurrentValue,"\n","OBV Average is ",OBVAVG,"\n","Previous four OBV Values: ", 
      "\n", "1= ",OBVPrevValue1,"\n", "2= ",OBVPrevValue2,"\n", "3= ",OBVPrevValue3,"\n", "4= ",OBVPrevValue4);
   }
   
   if(OBVCurrentValue<OBVAVG)
   {
      Comment("OBV is weak","\n","OBV current is ",OBVCurrentValue,"\n","OBV Average is ",OBVAVG,"\n","Previous four OBV Values: ",
      "\n", "1= ",OBVPrevValue1,"\n", "2= ",OBVPrevValue2,"\n", "3= ",OBVPrevValue3,"\n", "4= ",OBVPrevValue4);
   }
   
  }
//+------------------------------------------------------------------+
  • 此代码中的区别:

为 OBV 值创建五个数组:

double OBVArray0[];
double OBVArray1[];
double OBVArray2[];
double OBVArray3[];
double OBVArray4[];

这些数组的排列顺序均从当前数据开始:

ArraySetAsSeries(OBVArray0,true);   
ArraySetAsSeries(OBVArray1,true);
ArraySetAsSeries(OBVArray2,true);
ArraySetAsSeries(OBVArray3,true);
ArraySetAsSeries(OBVArray4,true);

用已定义的 OBVDef 填充它们:

CopyBuffer(OBVDef,0,0,5,OBVArray0);
CopyBuffer(OBVDef,0,0,5,OBVArray1);
CopyBuffer(OBVDef,0,0,5,OBVArray2);
CopyBuffer(OBVDef,0,0,5,OBVArray3);
CopyBuffer(OBVDef,0,0,5,OBVArray4);

获取当前和前四个 OBV 的值:

double OBVCurrentValue=NormalizeDouble(OBVArray0[0],5);         
double OBVPrevValue1=NormalizeDouble(OBVArray1[1],5);
double OBVPrevValue2=NormalizeDouble(OBVArray2[2],5);
double OBVPrevValue3=NormalizeDouble(OBVArray3[3],5);
double OBVPrevValue4=NormalizeDouble(OBVArray4[4],5);

在为 OBVAVG 创建双精度型变量后,计算前四个 OBV 值的平均值:

double OBVAVG=((OBVPrevValue1+OBVPrevValue2+OBVPrevValue3+OBVPrevValue4)/4);

设置 OBV 走强和走弱的条件及注释:

if(OBVCurrentValue>OBVAVG)
{
 Comment("OBV is strong","\n","OBV current is ",OBVCurrentValue,"\n","OBV Average is ",OBVAVG,"\n","Previous four OBV Values: ", 
  "\n", "1= ",OBVPrevValue1,"\n", "2= ",OBVPrevValue2,"\n", "3= ",OBVPrevValue3,"\n", "4= ",OBVPrevValue4);
}
   
if(OBVCurrentValue<OBVAVG)
{
 Comment("OBV is weak","\n","OBV current is ",OBVCurrentValue,"\n","OBV Average is ",OBVAVG,"\n","Previous four OBV Values: ",
  "\n", "1= ",OBVPrevValue1,"\n", "2= ",OBVPrevValue2,"\n", "3= ",OBVPrevValue3,"\n", "4= ",OBVPrevValue4);
}

编译后,我们将在导航器窗口中找到与如下相同的智能系统:

OBV nav3

以下是选择文件,并在 MetaTrader 5 上执行后的窗口:

简单 OBV 走强窗口

按下“确定”按钮后,智能系统加载到图表,并与下图相同:

简单 OBV 走强加载

以下是根据信号测试的示例,

走强 OBV:

简单 OBV 走强信号

走弱 OBV:

简单 OBV 走弱信号

  • 策略三: 简单 OBV - 上行趋势:

根据这一策略,在上升趋势期间,我们需要检查我们是否有更高的价格,同时,我们有更高的 OBV 值。 若有,我们需要检查当前 OBV 值是否大于前值,如果当前价格高点大于前价格高点,那么我们得到一个“在上升趋势中强劲移动”的信号。 以下是创建该策略的完整代码:

//+------------------------------------------------------------------+
//|                                         Simple OBV - Uptrend.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
void OnTick()
  {
   //creating a string variable for signal
   string signal="";
   
   //creating two OBV arrays for OBV
   double OBVArray0[];
   double OBVArray1[];
   
   //creating two price arrays
   MqlRates PriceArray0[];
   MqlRates PriceArray1[];
   
   //sorting OBV arrays from the current data
   ArraySetAsSeries(OBVArray0,true);   
   ArraySetAsSeries(OBVArray1,true);   
   
   //sorting Price arrays from the current data
   ArraySetAsSeries(PriceArray0,true);
   ArraySetAsSeries(PriceArray1,true);     
      
   //fill arrays with price data
   int Data0=CopyRates(_Symbol,_Period,0,3,PriceArray0);
   int Data1=CopyRates(_Symbol,_Period,0,3,PriceArray1);
   
   //defining OBV
   int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);

   //defining EA, buffer, sorting in arrays
   CopyBuffer(OBVDef,0,0,3,OBVArray0);
   CopyBuffer(OBVDef,0,0,3,OBVArray1);
            
   //getting the value of current & the previous OBV
   double OBVCurrentValue=NormalizeDouble(OBVArray0[0],5);         
   double OBVPrevValue=NormalizeDouble(OBVArray1[1],5);
    
   //getting the value of current high & the previous high
   double CurrentHighValue=NormalizeDouble(PriceArray0[0].high,5);         
   double PrevHighValue=NormalizeDouble(PriceArray1[1].high,5); 
      
   //strong move signal
   //if OBVCurrentValue>OBVPrevValue && current high> previous high
   if(OBVCurrentValue > OBVPrevValue && PriceArray0[0].high>PriceArray0[1].high)
   {
      signal="Strong move during uptrend";
   }

   //comment with the signal
   Comment("The signal is ",signal,"\n","OBVCurrentValue is :",OBVCurrentValue,
   "\n","OBVPrevValue is :", OBVPrevValue,"\n","Current high is :",CurrentHighValue,"\n","Previous high is :",PrevHighValue);            
  }
//+------------------------------------------------------------------+

此代码中的区别:

为“信号”创建一个字符串型变量,存储内容赋值为空的文本字符串,我们将在稍后计算:

string signal="";

为 OBV 创建两个 “double” 型数组,和两个 “MqlRates” 型价格数组,用来存储价格、交易量和点差信息:

//creating two OBV arrays for OBV
double OBVArray0[];
double OBVArray1[];
   
//creating two price arrays
MqlRates PriceArray0[];
MqlRates PriceArray1[];1[];

这些数组的排列顺序均从当前数据开始:

//sorting OBV arrays from the current data
ArraySetAsSeries(OBVArray0,true);   
ArraySetAsSeries(OBVArray1,true);   
   
//sorting Price arrays from the current data
ArraySetAsSeries(PriceArray0,true);
ArraySetAsSeries(PriceArray1,true);

为每个数组创建 Data0 和 Data1 整数型变量后,调用 “CopyRates” 函数获取 “MqlRates” 结构的历史数据,并填充价格数组:

int Data0=CopyRates(_Symbol,_Period,0,3,PriceArray0);
int Data1=CopyRates(_Symbol,_Period,0,3,PriceArray1);

定义 OBV,并用其填充两个 OBVArray:

int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);

CopyBuffer(OBVDef,0,0,3,OBVArray0);
CopyBuffer(OBVDef,0,0,3,OBVArray1);

获取 OBV 值和高点:

//getting the value of current & the previous OBV
double OBVCurrentValue=NormalizeDouble(OBVArray0[0],5);         
double OBVPrevValue=NormalizeDouble(OBVArray1[1],5);
    
//getting the value of current high & the previous high
double CurrentHighValue=NormalizeDouble(PriceArray0[0].high,5);         
double PrevHighValue=NormalizeDouble(PriceArray1[1].high,5); 

设置“上升趋势中的强势移动”条件,并显示在注释里:

Comment("The signal is ",signal,"\n","OBVCurrentValue is :",OBVCurrentValue,
"\n","OBVPrevValue is :", OBVPrevValue,"\n","Current high is :",CurrentHighValue,"\n","Previous high is :",PrevHighValue); 

如果我们编译代码,我们将在导航器窗口中找到智能系统:

OBV nav4

选择 MetaTrader 5 要上执行的文件后,智能系统窗口如下所示:

简单 OBV - 上行趋势窗口。

按下“确定”按钮后,智能系统加载到图表,并与下图相同:

简单 OBV - 上行趋势加载

以下是信号测试的示例,

针对当前数据的数据窗口信号:

当前数据的简单 OBV 上升趋势信号,含有窗口

先前数据的信号与数据窗口:

简单 OBV - 前一个数据的上升趋势信号,含有数据窗口

  • 策略四: 简单 OBV - 下行趋势:

根据这一策略,它将与简单 OBV-上升趋势策略相反,因为我们需要检查我们是否有一个更低的价格,同时,我们有一个更低的 OBV 值。 因此,我们需要检查 OBV 当前值是否低于前值,如果当前的价格低点低于先前的价格低点,那么我们就得到一个“下跌期间强劲移动”的信号。 以下是创建该策略的完整代码:


//+------------------------------------------------------------------+
//|                                       Simple OBV - Downtrend.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
void OnTick()
  {
   //create a string variable for signal
   string signal="";
   
   //creating two OBV arrays
   double OBVArray0[];
   double OBVArray1[];
   
   //creating two price arrays
   MqlRates PriceArray0[];
   MqlRates PriceArray1[];
   
   //sorting OBV arrays from the current data
   ArraySetAsSeries(OBVArray0,true);   
   ArraySetAsSeries(OBVArray1,true);   
   
   //sorting Price arrays from the current data
   ArraySetAsSeries(PriceArray0,true);
   ArraySetAsSeries(PriceArray1,true);     
      
   //fill array with price data
   int Data0=CopyRates(_Symbol,_Period,0,3,PriceArray0);
   int Data1=CopyRates(_Symbol,_Period,0,3,PriceArray1);
   
   //defining OBV
   int OBVDef =iOBV(_Symbol, _Period,VOLUME_TICK);

   //defining EA, buffer, sorting in arrays
   CopyBuffer(OBVDef,0,0,3,OBVArray0);
   CopyBuffer(OBVDef,0,0,3,OBVArray1);
            
   //getting the value of current OBV & the previous value
   double OBVCurrentValue=NormalizeDouble(OBVArray0[0],5);         
   double OBVPrevValue=NormalizeDouble(OBVArray1[1],5);
    
   //getting the value of current OBV & the previous value
   double CurrentLowValue=NormalizeDouble(PriceArray0[0].low,5);         
   double PrevLowValue=NormalizeDouble(PriceArray1[1].low,5); 
       
   //strong move signal
   //if OBVCurrentValue>OBVPrevValue && current low> previous low
   if(OBVCurrentValue < OBVPrevValue && PriceArray0[0].low<PriceArray0[1].low)
   {
      signal="Strong move during downtrend";
   }

   //comment with the signal
   Comment("The signal is ",signal,"\n","OBVCurrentValue is :",OBVCurrentValue,
   "\n","OBVPrevValue is :", OBVPrevValue,"\n","Current low is :",CurrentLowValue,"\n","Previous low is :",PrevLowValue);            
  }
//+------------------------------------------------------------------+
  • 此代码中的区别:

设置“下降趋势中的强势移动”条件,并显示在注释里:

Comment("The signal is ",signal,"\n","OBVCurrentValue is :",OBVCurrentValue,
"\n","OBVPrevValue is :", OBVPrevValue,"\n","Current low is :",CurrentLowValue,"\n","Previous low is :",PrevLowValue); 

现在,我们要编译它,然后我们可以在导航器窗口中找到该智能系统,如下所示:

OBV nav5

将此文件拖放到图表上后,将出现以下窗口:

简单 OBV - 下行趋势窗口

按下“确定”按钮后,智能系统加载图表,并与下图相同:

简单 OBV - 下行趋势加载

以下是基于测试生成的信号示例:

当前数据的信号及数据窗口

简单 OBV - 下降趋势信号及当前数据窗口

前一个数据的信号及数据窗口:

简单 OBV - 下降趋势信号及前一个数据窗口


结束语

在本文结束语当中,我们学习了另一个新的技术指标,该指标在计算中采用交易量,以另一个视角来查看图表,从而强化我们的交易决策。 这个指标是能量潮(OBV),我们在学习 OBV 指标时对它进行了详细了解,它测量了什么,我们如何手工计算它,以及掌握它的基础之外隐藏了什么。 我们还学习了如何根据其基础知识运用它,并学习了一些简单的策略,这些策略可能有用,或可帮助我们实现能构盈利的新思路,这是本文和本系列其它文章的主要目标。 我们为上述每种策略设计了一个蓝图,来帮助我们为每种策略编写代码,为它们创建一个交易系统。 此后,我们以 MQL5(MetaQuotes 语言)为每个提到的策略创建了一个智能系统,在 MetaTrader 5 交易平台中能够执行这些策略,并根据每个策略的预设条件和规则准确地自动生成信号。

我想提醒的是,技术分析中最有益的事情之一是,根据我们使用的工具,我们可以从金融工具的多个视角观察它,我们还可以组合多个工具或指标,特别是我们能够用一些工具来查看金融工具的全貌,从而清晰地做出相应的决策,这种方法有助于我们创建一个可靠的交易系统。 因此,在阅读或学习任何东西时,请您把这种方法摆在前面,以便能够意识到哪种工具可以与其它工具配合使用,从而为您提供更清晰的见解和更好的结果。

我需要再次强调,本文和本系列中的其它文章仅用于教学目的,仅针对初学者设计,目的是了解事物的根源,并认识到我们可以通过编程做些什么,特别是通过 MQL5,以及它在多大程度上能帮助我们简化和增强我们的交易业务。 您必须在使用任何策略之前进行测试,因为没有任何策略可以适合所有人,您必须测试和验证任何策略,从而确认它是否对您有用。 我建议您自行运用所学的一切来加深您的学习和理解。

我希望您能发现这篇文章很有用处,我亦希望您能理解这篇文章的主题,或交易领域的任何相关主题。 如果您发现本文很有用处,并且希望阅读类似的文章,您可阅读我之前发表的本系列文章,学习如何基于流行的技术指标设计交易系统。

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

带有图表交互控件的指标 带有图表交互控件的指标
本文提供了一个关于指标界面的新视角。 我将重点关注便利性。 多年以来,我尝试了几十种不同的交易策略,并测试过数百种不同的指标,我得出了一些结论,我想在本文中与大家分享。
神经网络变得轻松(第十五部分):利用 MQL5 进行数据聚类 神经网络变得轻松(第十五部分):利用 MQL5 进行数据聚类
我们继续研究聚类方法。 在本文中,我们将创建一个新的 CKmeans 类来实现最常见的聚类方法之一:k-均值。 在测试期间,该模型成功地识别了大约 500 种形态。
DoEasy. 控件(第 6 部分):面板控件,自动调整容器大小来适应内部内容 DoEasy. 控件(第 6 部分):面板控件,自动调整容器大小来适应内部内容
在本文中,我将继续研究面板 WinForms 对象,并实现自动调整大小,以便适应位于面板内的 Dock 对象的常规大小。 此外,我将向品种函数库对象添加新属性。
从头开始开发智能交易系统(第 16 部分):访问 web 上的数据(II) 从头开始开发智能交易系统(第 16 部分):访问 web 上的数据(II)
掌握如何从网络向智能交易系统输入数据并非那么轻而易举。 如果不了解 MetaTrader 5 提供的所有可能性,就很难做到这一点。