首页 技术指标 帖子

一键展示所有时间框架当前趋势的图形面板 - MetaTrader 4 指标

附件
15620.zip (2.17 KB, 下载 0次)

大家好!今天我想和大家分享一个非常实用的图形指标,它基于斜率方向趋势指标,经过一些小修改后,可以在屏幕上以图形面板的形式展示所有时间框架的趋势。

虽然市面上已经有多个版本的这个指标,但没有一个能在一个图形面板中显示所有时间框架的趋势。我对这个指标进行了改进,使其能够更好地服务于交易者。

如果你对这个指标感兴趣,可以在这里查找更多信息:斜率方向线搜索.

我增加了一个功能,允许用户选择第二个移动平均平滑的方法。原来的代码使用线性加权法进行第二次计算,而我则提供了选择平滑方法的选项。使用线性加权法会使得指标过于灵敏,可能会给出错误的当前趋势信号。而如果使用简单平均法作为第二次计算,则能够得到一个更符合价格走势的趋势。

另外一个改进是,不仅能获取趋势的方向(上涨、下跌或平稳),还能够获取其数值。我会在接下来的文章中,详细介绍如何利用双斜率方向指标创建一个EA(专家顾问)。

SlopeDirection

接下来,我们快速看一下代码的实现。首先,我定义了所有将要使用的对象名称。这是一个良好的编程习惯,因为每次在代码中引号中插入对象名称时,它会为该对象分配空间。因此,只需通过定义语句定义一次,便可节省代码空间。

// 定义趋势方向
#define     UPTREND           1
#define     DOWNTREND         -1
#define     FLATTREND         0

// 定义对象
#define     TrendPanel        "TrendPanel"
#define     InfoLine1         "InfoLine1"
#define     InfoLine2         "InfoLine2"
#define     TrendLabel        "趋势:  M1  M5  M15  M30  H1  H4  D1  W1  MN"
#define     TrendUp           "\233"
#define     TrendDown         "\234"
#define     TrendFlat         "\232"
#define     TrendUnknown      "\251"
#define     StatObjectError   "%s(%d) 创建'%s'失败.  错误 = %d"

接下来,我定义了两个数组。一个是每个时间框架的像素位置,另一个是时间框架。这些都被定义为全局变量。

// 定义全局变量
int      TrendPosition[] = { 44, 64, 88, 114, 136, 156, 174, 194, 216 };
int      TrendPeriods[] = { PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 };

我们的指标OnInit()函数会调用一个函数来创建面板和面板内的对象。同时,它也会对用于计算趋势的K线进行快速检查,少于3根K线计算趋势基本没有意义。

//+------------------------------------------------------------------+
//| 自定义指标初始化函数                         |
//+------------------------------------------------------------------+
int   OnInit()
{
   // 创建指标面板的对象
   if(Create_Panel() && BarCount >= 3)
      return(INIT_SUCCEEDED);
   else
      return(INIT_FAILED);
}

关于GetTrend()函数的具体工作原理我不打算深入讨论,这里有许多优秀的文档可以参考。我们先来看一下图形显示趋势的DisplayTrend()函数。

//+------------------------------------------------------------------+
//| 显示所有时间框架的当前趋势
//+------------------------------------------------------------------+
void  DisplayTrend(void)
{
   int      i, cntr, Trend, LastTrend;
   string   str;
   
   for(i=1; i<10; i++)
   {
      str = "趋势" + DoubleToStr(i, 0);
      Trend = (int)GetTrend(TrendPeriods[i-1], BarCount, Method);
      if(Trend == FLATTREND)
      {
         // 如果趋势平稳,查找最后的趋势方向
         cntr = 1;
         do 
         { 
            LastTrend = (int)GetTrend(TrendPeriods[i-1], BarCount, Method, false, cntr++);
         } while(LastTrend == Trend);
         ObjectSetText(str, TrendFlat, 8, "WingDings", (LastTrend == UPTREND ? Green : Red));
         ObjectSetInteger(0, str, OBJPROP_YDISTANCE, 6);
      }
      else
      {
         ObjectSetText(str, (Trend == UPTREND ? TrendUp : TrendDown), 8, "WingDings", (Trend == UPTREND ? Green : Red));
         ObjectSetInteger(0, str, OBJPROP_YDISTANCE, 5 + (Trend == UPTREND ? 1 : -1));
      }
   }
}

基本上,我们循环遍历TrendPeriods[]数组(以获取所有时间框架)并根据该时间框架的趋势方向设置趋势箭头。如果趋势是平坦的,我们会找到第一个非平坦的方向,以了解趋势的来源,并以该方向的颜色显示箭头。

在OnInit()中的Create_Panel()函数创建了锚定在屏幕左下角的对象,并使用TrendPosition[]将箭头放置在正确的位置。

//+------------------------------------------------------------------+
//| 在屏幕左下角创建趋势面板
//+------------------------------------------------------------------+
bool  Create_Panel(void)
{

   int      i;
   string   str;
   
   // 创建趋势指标窗口
   if(ObjectCreate(TrendPanel, OBJ_RECTANGLE_LABEL, 0, 0, 0))
   {
      ObjectSetInteger(0, TrendPanel, OBJPROP_XDISTANCE, 1);
      ObjectSetInteger(0, TrendPanel, OBJPROP_YDISTANCE, 29);
      ObjectSetInteger(0, TrendPanel, OBJPROP_XSIZE, 240);
      ObjectSetInteger(0, TrendPanel, OBJPROP_YSIZE, 26);
      ObjectSetInteger(0, TrendPanel, OBJPROP_BGCOLOR, White);
      ObjectSetInteger(0, TrendPanel, OBJPROP_BORDER_TYPE, 0);
      ObjectSetInteger(0, TrendPanel, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSetInteger(0, TrendPanel, OBJPROP_COLOR, Red);
      ObjectSetInteger(0, TrendPanel, OBJPROP_STYLE, STYLE_SOLID);
      ObjectSetInteger(0, TrendPanel, OBJPROP_WIDTH, 2);
      ObjectSetInteger(0, TrendPanel, OBJPROP_BACK, false);
      ObjectSetInteger(0, TrendPanel, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, TrendPanel, OBJPROP_SELECTED, false);
      ObjectSetInteger(0, TrendPanel, OBJPROP_HIDDEN, true);
      ObjectSetString(0, TrendPanel, OBJPROP_TOOLTIP, "\n");
   }
   else
   { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, TrendPanel, GetLastError()); return(false); }

   if(ObjectCreate(InfoLine1, OBJ_LABEL, 0, 0, 0))
   {
      ObjectSet(InfoLine1, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSet(InfoLine1, OBJPROP_XDISTANCE, 6);
      ObjectSet(InfoLine1, OBJPROP_YDISTANCE, 15);
      ObjectSetInteger(0, InfoLine1, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, InfoLine1, OBJPROP_HIDDEN, true);
      ObjectSetString(0, InfoLine1, OBJPROP_TOOLTIP, "\n");
      ObjectSetText(InfoLine1, TrendLabel, 8, "Arial", Black);
   }
   else
   { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, InfoLine1, GetLastError()); return(false); }
   
   if(ObjectCreate(InfoLine2, OBJ_LABEL, 0, 0, 0))
   {
      ObjectSet(InfoLine2, OBJPROP_CORNER, CORNER_LEFT_LOWER);
      ObjectSet(InfoLine2, OBJPROP_XDISTANCE, 6);
      ObjectSet(InfoLine2, OBJPROP_YDISTANCE, 5);
      ObjectSetInteger(0, InfoLine2, OBJPROP_SELECTABLE, false);
      ObjectSetInteger(0, InfoLine2, OBJPROP_HIDDEN, true);
      ObjectSetString(0, InfoLine2, OBJPROP_TOOLTIP, "\n");
      ObjectSetText(InfoLine2, " " + DoubleToStr(BarCount, 0) + " / " + DoubleToStr(Method, 0), 8, "Arial", Black);
   }
   else
   { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, InfoLine2, GetLastError()); return(false); }

   // 创建趋势对象并显示当前趋势    
   for(i=1; i<10; i++)
   {
      str = "趋势" + DoubleToStr(i, 0);
      if(ObjectCreate(str, OBJ_LABEL, 0, 0, 0))
      {
         ObjectSet(str, OBJPROP_CORNER, CORNER_LEFT_LOWER);
         ObjectSet(str, OBJPROP_XDISTANCE, TrendPosition[i-1]);
         ObjectSet(str, OBJPROP_YDISTANCE, 5);
         ObjectSetInteger(0, str, OBJPROP_SELECTABLE, false);
         ObjectSetInteger(0, str, OBJPROP_HIDDEN, true);
         ObjectSetString(0, str, OBJPROP_TOOLTIP, "\n");
      }
      else
      { PrintFormat(StatObjectError, __FUNCTION__, __LINE__, str, GetLastError()); return(false); }
   }

   // 显示当前趋势
   DisplayTrend();
      
   // 一切正常
   return(true);
}

这个函数如果成功创建所有对象,将返回TRUE,否则返回FALSE。值得一提的是,指标会在控制台的EXPERT标签中显示错误代码以及出错的代码行号。

我们还需要在每个新tick到达时更新趋势指标,这通过在start()函数中调用DisplayTrend()函数来实现。

//+------------------------------------------------------------------+
//| 自定义指标迭代函数                              |
//+------------------------------------------------------------------+
int   start()
{
   // 显示所有时间框架的当前趋势
   DisplayTrend();   

   return(0);
}

最后,当我们关闭指标时,需要销毁所有由指标创建的对象。

//+------------------------------------------------------------------+
//| 去初始化函数                                         |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // 删除指标的对象
   if(ObjectFind(TrendPanel) >= 0) ObjectDelete(TrendPanel);
   if(ObjectFind(InfoLine1) >= 0) ObjectDelete(InfoLine1);
   if(ObjectFind(InfoLine2) >= 0) ObjectDelete(InfoLine2);
   for(int i=1; i<10; i++)
      if(ObjectFind("趋势"+DoubleToStr(i, 0)) >= 0) ObjectDelete("趋势"+DoubleToStr(i, 0));
}

就是这样。现在你有一个实用的指标面板,可以显示所有时间框架的当前趋势,位置在屏幕的左下角。

希望你们喜欢这个指标!


相关帖子

评论 (0)