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

量化交易吧 /  量化策略 帖子:3364704 新帖:25

在指标中添加声音提醒

只求稳定发表于:4 月 17 日 19:46回复(1)

简介

尽管自动化交易变得越来越常见,但很多交易者仍在进行手动交易。Expert Advisor 只要几毫秒时间即可评估当前市场情况,而人则需要花费许多时间、精力和最为重要的关注度才能完成当前市场状况评估。

几年前,很多交易者使用一个或多个技术指标。一些策略同时考虑多个时间范围的指标值。

那么,如何能够“抓住”重要的信号?有多种选择:

  • 编写一个能够分析市场并对重要事件进行提醒的 Expert Advisor;
  • 坐在显示器前,在数十个图表中来回切换,尝试分析所有图表中的信息;
  • 将提醒系统添加到使用的所有指标中。

我个人认为,第一种选择最为合适。但是,需要有编程技能或支付相关费用才能实现。第二种方式非常耗时、累人,而且效率低下。第三种选择介于前两种方式之间。只要少得多的技能和时间即可实现,但的确可以帮助很多手动交易用户。

本文专门介绍第三种选择的实施情况。阅读本文后,每位交易者将能够将便捷的提醒添加到指标中。



提醒的类型

有很多种方式来解释指标。人们甚至对 MetaTrader 4 客户端的指标的含义都存在不同的理解,更别提各种自定义指标...

一名交易者会在 MACD 的主线触及信号线时买入,另一名交易者会等到与零线相交时才买入,而还有交易者会在 MACD 小于 0 且开始向上移动时才建立多头头寸。我觉得自己无法统计所有可能的不同解释,因此,我将仅介绍如何将提醒模块加入到指标的原则。这样,您将能够根据喜好将任意类型的提醒添加到几乎所有的指标中。

下面列出了最可能的提醒:

  • 指标的两条线的相交(在上例中为 MACD 的主线和信号线);
  • 指标线与某水平的相交(例如,MACD 的主线与零线,Stoсhastic 与 70 和 30 水平,CCI 与 -100 和 100 水平);
  • 指标的反向移动(例如,AC 与 AO,正常 MA);
  • 位置朝向价格而变化(抛物线 SAR);
  • 出现高于或低于价格值的箭头(分形)。

很可能还有其他一些我已遗忘或根本不了解的解释,因此,我们将介绍上述列出的五种类型。


提醒的方式

MetaTrader 4 和 MQL4 允许实现多种可视和音频提醒方式。

  • 常见的屏幕消息(备注函数);
  • 日志中的记录(打印函数);
  • 消息窗口及声音(提醒函数);
  • 特殊声音,待选择和播放的文件(PlaySound 函数)。

除此之外,还有用于将文件发送至 FTP 服务器的函数(SendFTP() 函数)、用于显示消息/对话框的函数(MessageBox() 函数) 和用于发送邮件的函数(SendMail() 函数)。函数 SendFTP() 几乎不被普通用户所使用;函数 MessageBox() 因其在消息框关闭之后才停止操作而不适用于在指标中使用;尽管函数 SendMail() 很适合发送短信,但使用过程中相当“危险” - 在图表上绘制大量指标,会无休止地收到不受控的消息。可使用此函数,但最好是在以下情况下使用,例如,当多个指标上同时出现一个提醒时,从 EA 发送一条消息,对其给予密切关注。

在本文中,我们将仅考虑 MetaTrader 4 客户端中的音频和可视提醒方式。

这些函数中的一个最便捷和最简单函数就是提醒函数,因为它同时包含文本和声音内容。除此之外,终端将存储提醒的历史记录,因此可查看一个小时之前收到了什么信号。

但是大家都知道,每个人的偏好各有不同。因此,我将为上述所有方法(SendFTP、MessageBox、SendMail 除外)制定一个类似预制定的模型,您只需选择合适的选项。


提醒频率过滤器

如果您在指标中使用了提醒,您当然得处理它们的过频率,尤其是有关较小时间范围的过频率。有一些方法解决此问题:

  • 在已形成的柱上定义提醒。此解决方案最为合适。
  • 交替提醒 - 先买后卖,反之亦然(这也是一种非常合理的方式,可与其他方式一起使用)。
  • 在两次提醒之间设置暂停(不是个好主意)。
  • 每个柱仅提供一次提醒(此限制相当受影响)。

是否使用从零而非从已形成的柱定义的提醒取决于个人。例如,我认为这不对。但是,存在需要即时响应的指标,对于它们而言,一个柱也太久了。因此,我们允许用户做出自己的选择。多次购买提醒几乎没有什么意义,因此我们将交替发出所有提醒。我认为,我们不会引入任何人为的暂停。如果确实需要,可在本文的备注中了解具体情况。

因此,让我们开始实施。


第一种提醒 - 指标的两条线的相交

让我们开始使用上述示例中给出的 MACD。

我们的主要任务是检测出指标线存储在哪个数组中。我们来看看相关代码:

//---- indicator settings
#property  indicator_separate_window
#property  indicator_buffers 2
#property  indicator_color1  Silver
#property  indicator_color2  Red
#property  indicator_width1  2
//---- indicator parameters
extern int FastEMA = 12;
extern int SlowEMA = 26;
extern int SignalSMA = 9;
//---- indicator buffers
double MacdBuffer[];
double SignalBuffer[];

请注意,“指标缓冲器”的备注是我们要查找的内容。这些数组大多数都有直观而全面的名称(MacdBuffer 是 MACD 主线值缓冲器,SignalBuffer - 信号线的缓冲器),并且始终处于函数 init、deinit、start 之外。

如果有很多数组并且难以查看哪个数组为必要数组,请查看函数 init - 图表中显示的所有数组都被固定到某个使用函数 SetIndexBuffer 的数字:

int init()
  {
//---- drawing settings
   SetIndexStyle(0, DRAW_HISTOGRAM);
   SetIndexStyle(1, DRAW_LINE);
   SetIndexDrawBegin(1, SignalSMA);
   IndicatorDigits(Digits + 1);
//---- indicator buffers mapping
   SetIndexBuffer(0, MacdBuffer);
   SetIndexBuffer(1, SignalBuffer);
//---- name for DataWindow and indicator subwindow label
   IndicatorShortName("sMACD(" + FastEMA + "," + SlowEMA + "," + SignalSMA + ")");
   SetIndexLabel(0, "sMACD");
   SetIndexLabel(1, "sSignal");
//---- initialization done
   return(0);
  }

这是序列(0 至 7),在此序列中,指标线的值显示在 DataWindow 中。您在那里看到的名称是由函数 SetIndexLabel 给定的 - 这是第三种标识方法。

现在,当我们了解了必要数据存储在何处时,我们可以开始实现提醒模块。为此,我们将转到函数 start 的结尾部分 - 正好位于前一操作符 return 的上方:

for(i = 0; i < limit; i++)
       SignalBuffer[i] = iMAOnArray(MacdBuffer, Bars,S ignalSMA, 0, MODE_SMA, i);
//---- done
 
// we will add our code here
 
   return(0);
  }
//+------------------------------------------------------------------+

在任何情况下,都不得在指标的计算回路中添加任何提醒块 - 这会减慢执行速度,而且没有任何作用。

让我们开始编写我们的“composition”:

//---- Static variables where the last bar time
    //---- and the last alert direction are stored
    static int PrevSignal = 0, PrevTime = 0;
 
    //---- If the bar selected to be analyzed is not a zero bar, 
    //     there is no sense to check the alert
    //---- several times. If no new bar starts to be formed, quit.
    if(SIGNAL_BAR > 0 && Time[0] <= PrevTime ) 
        return(0);
    //---- Mark that this bar was checked
    PrevTime = Time[0];

每次开始执行函数 start 时,也会执行我们的代码。每次执行此函数之后,正常变量都会归零。因此,我们声明了两个静态变量以存储最新提醒和计算出的柱编号。

然后进行简单的检查:我们检查新的柱是否已启动(它只有在 SIGNAL_BAR 大于 0 时才有效)。

顺便说一下,我们稍早于函数 init 之前声明了变量 SIGNAL_BAR 本身:

double     SignalBuffer[];
 
//---- Bar number the alert to be searched by
#define SIGNAL_BAR 1
 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {

请注意指令 #define - 在整个代码中,编译器将仅用给定值 (1) 替换变量 SIGNAL_BAR。

下面是提醒代码本身:

//---- If the preceding alert was SELL or this is the first launch (PrevSignal=0)
    if(PrevSignal <= 0)
      {
        //---- Check whether the lines have met in the preceding bar:
        if(MacdBuffer[SIGNAL_BAR] - SignalBuffer[SIGNAL_BAR] > 0 && 
           SignalBuffer[SIGNAL_BAR+1] - MacdBuffer[SIGNAL_BAR+1] >= 0)
          {
            //---- If yes, mark that the last alert was BUY
            PrevSignal = 1;
            //---- and display information:
            Alert("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            Print("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            Comment("sMACD (", Symbol(), ", ", Period(), ")  -  BUY!!!");
//            PlaySound("Alert.wav");
          }
      }

这也非常简单。如果之前的提醒为 SELL,检查线的相交情况:

如果柱 #1 上的 MACD 主线值超过了柱 # 1 上的信号线的值
并且
柱 #2 上的信号线值超过了柱 #2 上的 MACD 线的值,

线相交。

然后,标记最后一个提醒用于 BUY,并显示通知消息。请注意 三个有注释的线 - 它们是另外三种提醒。您可以取消注释 或删除它们中的任意或全部项。我将提醒默认为最便捷的方法。

在函数 PlaySound 中,可指定应播放的波形文件。此文件必须位于目录 MetaTrader 4\sounds\ 中并且必须具有扩展名 wav。例如,可将特殊声音指派给 BUY 提醒,另一个 - 用于 SELL 提醒,或者不同的指标使用不同的声音

SELL 提醒完全相同:

//---- Completely the same for the SELL alert
    if(PrevSignal >= 0)
      {
        if(SignalBuffer[SIGNAL_BAR] - MacdBuffer[SIGNAL_BAR] > 0 && 
           MacdBuffer[SIGNAL_BAR+1] - SignalBuffer[SIGNAL_BAR+1] >= 0)
          {
            PrevSignal = -1;
            Alert("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            Print("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            Comment("sMACD (", Symbol(), ", ", Period(), ")  -  SELL!!!");
//            PlaySound("Alert.wav");
          }
      }


其他提醒

现在,在我们了解了指标代码后,对于我们而言,编写其他提醒块要简单得多。将仅更改“公式”,代码的其他部分将仅进行复制和粘贴。

用于发出触及某水平的信号的提醒非常类似于各线相交的提醒。我将它添加到了 Stochastic 中,但是您可以为任何其他指标制定类似的提醒:

if(PrevSignal <= 0)
      {
        if(MainBuffer[SIGNAL_BAR] - 30.0 > 0 && 
           30.0 - MainBuffer[SIGNAL_BAR+1] >= 0)
          {
            PrevSignal = 1;
            Alert("sStochastic (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(70.0 - MainBuffer[SIGNAL_BAR] > 0 && 
           MainBuffer[SIGNAL_BAR+1] - 70.0 >= 0)
          {
            PrevSignal = -1;
            Alert("sStochastic (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

正如您所看到的,如果线路 %K (MainBuffer) 自下而上达到了 30 水平,指标会提示“买入”,而如果自上而下达到了 70 水平,则会提示“卖出”。

第三种提

//---- indicator buffers
double     ExtBuffer0[];
double     ExtBuffer1[];
double     ExtBuffer2[];
double     ExtBuffer3[];
double     ExtBuffer4[];

ExtBuffer3 和 ExtBuffer4 用于中间计算,ExtBuffer0 始终存储指标值,ExtBuffer2 和 ExtBuffer3“颜色”列使用 2 种颜色。由于我们只需要指标值,因此我们将使用 ExtBuffer0:

if(PrevSignal <= 0)
      {
        if(ExtBuffer0[SIGNAL_BAR] - ExtBuffer0[SIGNAL_BAR+1] > 0 &&
           ExtBuffer0[SIGNAL_BAR+2] - ExtBuffer0[SIGNAL_BAR+1] > 0)
          {
            PrevSignal = 1;
            Alert("sAC (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(ExtBuffer0[SIGNAL_BAR+1] - ExtBuffer0[SIGNAL_BAR] > 0 &&
           ExtBuffer0[SIGNAL_BAR+1] - ExtBuffer0[SIGNAL_BAR+2] > 0)
          {
            PrevSignal = -1;
            Alert("sAC (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

如果指标值在减小后开始增大,则我们会给出 BUY 提醒。反之,我们将给出 SELL 提醒。

第四种提醒 - 通知位置朝向价格而变化 - 这种提醒很少见。

但是,Parabolic 中偶尔会出现这种提醒。在示例中,我们使用它来编写“公式”:

if(PrevSignal <= 0)
      {
        if(Close[SIGNAL_BAR] - SarBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = 1;
            Alert("sParabolic Sub (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(SarBuffer[SIGNAL_BAR] - Close[SIGNAL_BAR] > 0)
          {
            PrevSignal = -1;
            Alert("sParabolic Sub(", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

它在此处非常简单 - 我们将指标值与柱接近价格进行比较。注意,如果 SIGNAL_BAR 设置为 0,Parabolic 的每次价格触及都会伴随提醒。

最后一次提醒通知图表中出现箭头。它在标准指标中极少出现,但在自定义的“枢轴查找器”中相当常见。我将考虑这种使用指标“分形”(其在 MQL4 中编写的源代码可在代码库:分形中找到)的提醒。

这种指标有一个共同的特点:在图表上绘制它们的地方,它们不等于0(或  EMPTY_VALUE)。在所有其他柱上,它们的缓冲区是空的。这意味着,您只需要将缓冲区的值与零作比较来确定信号:

if(PrevSignal <= 0 )
      {
        if(ExtDownFractalsBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = 1;
            Alert("sFractals (", Symbol(), ", ", Period(), ")  -  BUY!!!");
          }
      }
    if(PrevSignal >= 0)
      {
        if(ExtUpFractalsBuffer[SIGNAL_BAR] > 0)
          {
            PrevSignal = -1;
            Alert("sFractals (", Symbol(), ", ", Period(), ")  -  SELL!!!");
          }
      }

但是,如果您将具有此类代码的指标添加到图表上,您永远不会收到任何提醒。分形有一个特殊功能 - 它们使用 2 个未来的柱进行分析,因此仅柱 #2 上显示箭头(第三个柱以零开始)。要使提醒开始工作,需要将 SIGNAL_BAR 设置为 2:

//---- Bar number to search an alert by
#define SIGNAL_BAR 2

全部完毕,提醒将正常工作!



总结

本文介绍了用于将声音提醒添加到指标中的各种方法。定义了提醒解释方法(提醒类型)、提醒的方式提醒频率滤波器等术语。

定义并实现了以下提醒类型:

  • 指标的两条线的相交;
  • 指标线与某个水平的相交;
  • 指标的反向移动;
  • 位置朝向价格而变化;
  • 出现高于或低于价格值的箭头。
为提醒选择以下函数:
  • Comment() - 显示正常消息;
  • Print() - 在日志中显示消息;
  • Alert() - 在特殊窗口中显示消息并显示声音提醒;
  • PlaySound() - 播放任何波形文件。
降低提醒频率:
  • 使用确定提醒时已形成的柱;
  • 所有提醒交替出现 - 仅在卖出后买入,反之亦然。

我使用了五个对应于五种提醒的指标来研究它们的提醒块。您可以下载结果指标 - 它们已随附本文提供。

我希望您能明白,在将提醒块添加到指标的过程中没有任何复杂的操作 - 每个人都可以做到。

全部回复

0/140

量化课程

    移动端课程