有谁知道如何开发一个多货币指标? - 页 4

 

好了,伙计们,第一部分已经完成(读取所有货币对的汇率)。

现在我需要用ArrayCopyRates函数复制的所有巴黎货币的汇率来生成一些图形指标,如RSI...如下图所示。

在我最初的问题中,我想知道如何做到这一点......而不是关于阅读率。我不认为我需要在绘制之前复制费率,但知道如何做很好......现在我只需要发现一种方法来分割指标区域,以绘制所有货币对......

 
明白了。那么所有的元素都必须作为对象来绘制。
 

这是我在某个地方捡到的一个指标,我从来没有尝试去解读它。它显示了当前图表中3个时间段的表现。最疯狂的是蜡烛是用柱状图画出来的。很整洁,但不是我现在所喜欢的。

最好的祝愿

附加的文件:
 
好的,谢谢。我在工作中出差,回来后我要测试一下。
 
Fernando Carreiro:

给关注这个话题的人一个更新

我一直在通过PM帮助OP修复他的代码,因为他在英语方面有困难,而我们都讲葡萄牙语。在我们的测试中,我们遇到了另一个发生在"ArrayCopyRates()"函数中的 "趣事"。当在EA中用"ArrayCopyRates()"使用MqlRates 数组时,数据数组是一个虚拟数组,总是报告事物的当前状态,所以数据总是新鲜的。

然而,在一个指标中,情况似乎不是这样的。数组不是一个虚拟的副本,而是在调用"ArrayCopyRates()"时设置的一个静态副本。当符号与图表符号不同时,数据不会更新。当它与图表符号相同时,那么数组数据是 "活的",并按预期更新,但当它是另一个符号时,它是一个静态拷贝。

因此,为了让它在指标中发挥作用,如果需要新的数据,必须在每次调用OnCalculate()事件时调用 "ArrayCopyRates()"函数。

只是为了扩展你的发现,费尔南多--即使符号与图表符号相同,如果时间框架不同,那么数组是静态的。

因此,为了有一个虚拟副本,在一个指标中,它必须是相同的符号和相同的时间框架。其他都是静态的。

 
honest_knave: 只是为了扩大你的发现,费尔南多 - 即使符号与图表符号相同,如果时间框架不同,那么数组是静态的。因此,为了有一个虚拟副本,在一个指标中,它必须是相同的符号和相同的时间框架。其他都是静态的。
谢谢你的更新!
 
你好。

我一直在到处寻找这个问题的解决方案,我想感谢这个主题中的每个人的讨论。

这是我在论坛上的第一条信息,所以如果我错过了任何协议,请让我知道,我很乐意在下一条信息中纠正。

我正试图开发一个非常简单的指标,但我的逻辑似乎对图表是否完全更新很敏感,这就是为什么我对这个讨论如此感兴趣。

我的指标是在前一天的范围内画出一个纤维(当天高点到当天低点或当天低点到当天高点),在当天的高点、低点和纤维的50%处画线。如果该指标用于GMT经纪商(周日日线),用户可以设置一个输入参数,选择周一是否只使用周五或周日的范围,或周五+周日。在纽约收盘的经纪商(GMT+2),鉴于没有星期天的蜡烛,这并没有什么区别。

这个指标的另一个特点是允许用户移动纤维,当前日的线(高点、50%和低点)将调整到纤维设置的新范围。这将允许用户在范围收缩的情况下对范围进行调整。

该指标将主要用于多个1小时图表,但用户应该能够切换时间框架而不丢失在纤维上做出的任何变化。

为了绘制纤维,我不仅需要找到前一天的高点和低点,还需要找到这些点的时间。

这个想法很简单,但我一直面临一些挑战。

假设现在是周中,要找到前一天的高点和低点,我只需用。

       Hi = iHigh(NULL, PERIOD_D1, 1);
       Lo = iLow(NULL, PERIOD_D1, 1);

这很好,但现在我需要找到前一天的最高点和最低点是什么时间。我决定用iHighest和iLowest来估计1h蜡烛的高点和低点的时间。这时问题就开始了。


要使用iHighest和iLowest,我需要指定第一个1小时的蜡烛和范围的大小,因此在我的例子中,这将是前一天的第一个1小时和最后一个1小时的蜡烛。所以我用前一天的日蜡烛的开盘价作为前一天的开始,用当天日蜡烛的开盘价-1,来寻找前一天的结束。

       PrevDayBegin = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 1));                
       PrevDayEnd = iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1);

如果你只在货币上使用该指标(再次假设是在本周中),那效果很好,因为PrevDayBegin将是0:00 1h蜡烛的指数,PrevDayEnd将是23:00 1h蜡烛的指数。问题出在期货上(指数、黄金、原油等)。每天的蜡烛开盘时间总是在0:00,但是期货的第一根蜡烛是在GMT+2经纪商的凌晨1点,因此上面那行计算PrevDayBegin的代码返回前一天23:00的1h蜡烛。

于是我决定加入一段代码以适应这种情况,并将PrevDayBegin移动到与PrevDayEnd在同一个星期的日期。

       if(TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayBegin)) != TimeDayOfWeek(iTime(NULL, PERIOD_H1, PrevDayEnd)))
         PrevDayBegin--;  

如果你有最新的1小时蜡烛,所有的逻辑都很好用,但看看下面的日志,显示了今天发生的一些打印结果。作为参考,我在前一天晚上关闭了MT4,并在今天早上再次打开(英国早上7点左右),因此图表中只有几个小时的数据丢失。

2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == 本周的其他日子 ==
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.08 19:00)
2017.02.09 06:56:20.613 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 20 (2017.02.08 00:00)

看一下日志,似乎1h图表上最新的蜡烛是2017.02.08 20:00(索引0),因此iBarShift(NULL, PERIOD_H1, iTime(NULL, PERIOD_D1, 0)-1)是近似于(索引1)2017.02.08 19:00。因此,该指标的所有计算都被混淆了,因为iHighest和iLowest将使用错误的范围。

根据之前的讨论,我尝试并使用了一些建议的解决方案,等待所有的蜡烛被加载后再进行计算,但显然还是没有效果。

例如,在OnInit()中,我加入了以下几行代码,以触发图表在1h、Daily和当前时间框架上的更新(以防平台关闭时图表在不同时间框架上打开)。

   // Triggers history update
   MqlRates mqlrates_array_d1[];
   MqlRates mqlrates_array_h1[];
   MqlRates mqlrates_array[];
  
   ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1);
   ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1);
   ArrayCopyRates(mqlrates_array,NULL,0);  
我注意到的另一件事是,似乎MT4在加载所有缺失的历史记录之前,会在图表中打开的时间框架上更新最近的蜡烛图Time[0],因此我决定测试Time[1]是否也是一个有效价格。

这段代码被插入到OnCalculate()中,它基于@whroeder1(这里)和@Fernando Carreiro&@Wemerson Guimaraes(这里)的代码。

bool isHistoryLoading;

OnInit();
:
isHistoryLoading = true;
:

OnCalculate( ... )
:
      MqlRates mqlrates_array_d1[];
      MqlRates mqlrates_array_h1[];
      MqlRates mqlrates_array[];
      
      if(isHistoryLoading)
        {      
         ResetLastError();        
        
         if(ArrayCopyRates(mqlrates_array_d1,NULL,PERIOD_D1)>0)
           {
            if(GetLastError() == 0)
              {
               if((iTime(NULL,PERIOD_D1,0) > 0) && (iTime(NULL,PERIOD_D1,1) > 0))
                 {
                  ResetLastError();
  
                  if(ArrayCopyRates(mqlrates_array_h1,NULL,PERIOD_H1)>0)
                    {
                     if(GetLastError() == 0)
                       {
                        if((iTime(NULL,PERIOD_H1,0) > 0) && (iTime(NULL,PERIOD_H1,1) > 0))
                          {
                           ResetLastError();
      
                           if(ArrayCopyRates(mqlrates_array,NULL,0)>0)
                             {
                              if(GetLastError() == 0)
                                {
                                 if((iTime(NULL,0,0) > 0) && (iTime(NULL,0,1) > 0))                            
                                   {
                                    isHistoryLoading = false;
                                
                                    if(DebugLog)
                                      Print("Chart up-to-date!");        
                                    }
                                }
                             }
                          }
                       }
                    }                      
                 }
              }
           }
        }
        
      if(isHistoryLoading)
        {
         if(DebugLog)
           Print("Waiting for chart to update!");
         return(rates_total);
        }    

:

这是平台打开和指标首次加载时的日志。

2017.02.09 06:56:18.492 自定义指标Prev_Day_Range_LRT_50_v0.6 SPX500,H1:加载成功
2017.02.09 06:56:18.630 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: 已初始化
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: 图表最新!
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: 指标不存在!创建它。
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: ==本周其他日期 ==
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 20 (2017.02.07 23:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 42 (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Day of week = 3
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 28) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 20) (Price = 2287.88) (Time = 2017.02.07 23:00:001)
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib from Time1=2017.02.07 14:00 Price1=2299.33 to Time2=2017.02.07 23:00 Price2=2287.88
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 00:00 Price1=2299.33 to Time2=2017.02.09 00:00 Price2=2299.33
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 00:00 Price1=2293.605 to Time2=2017.02.09 00:00 Price2=2293.605
2017.02.09 06:56:18.639 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 00:00 Price1=2287.88 to Time2=2017.02.09 00:00 Price2=2287.88

似乎任何对蜡烛0和1的引用或ArrayCopyRates函数都只访问图表中已经加载的信息,因此ArrayCopyRates似乎正在返回复制的有效元素数量,iTime(..., 0)和iTime(..., 1)正在返回前一天平台关闭时存储的最后2根蜡烛的有效价格。

这意味着该指标是按照昨天的情况来绘制的(PERIOD_D1 [0] = (2017.02.08 00:00))。

该指标是这样构建的:即使用户移动了纤维,高线、50%和低线也总是绘制在当前日期(这就是上面日志中显示的3条趋势线)。因此,我在OnCalculate()上有一段代码,测试中间的趋势线是否在当日绘制(用户有一个输入选项可以禁用顶部和底部的线,所以唯一会一直绘制的是中间的线)。

OnCalculate( ... )
:

      if(ObjectFind(Trend2Name) != -1)                // Check whether mid range line exists
        {
            
         if((TimeDay(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeDay(TimeCurrent()))
           && (TimeMonth(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeMonth(TimeCurrent()))
           && (TimeYear(ObjectGetInteger(0,Trend2Name,OBJPROP_TIME,0))==TimeYear(TimeCurrent()))) // Indicator has already been ploted today        
           {
            return(rates_total);
           }
         else     // Indicator exists but in a past date, so delete it and plot it on current day
           {
            if(DebugLog)
               Print("Indicator in a past date! Deleting it and creating it today!");
              
            if(ObjectFind(FibName) != -1)
              FiboLevelsDelete(0,FibName);              
            // Indicator will be created by the OnChartEvent() when it detects the fib was deleted.
           }
        }
      else        // Indicator doesn't exist, so create it
        {
         if(DebugLog)
            Print("Indicator doesn't exist! Creating it.");
         CreateIndicator();
        }
:

在几个点之后,数据被部分加载,上面的这段代码将检测到这些线是在前一天绘制的,删除纤维并触发范围的重新计算和对象的重新绘制(即纤维、趋势线等)。


2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: 指标在过去的日期!删掉它并在今天创建它!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDRFibo 131296489639296384删除!
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRRectangle 131296489639296384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend1 131296489639384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend2 131296489639384
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Deleting PDRTrend3 131296489639296384

然后我们又回到了我在本消息开始时提到的问题。我在上面实现的测试又没有让指标等待历史数据被完全加载,因此根据部分数据计算出的范围是错误的。

这是信息开头显示的日志的更完整版本,显示不仅PrevDayEnd被错误计算为1小时图中的第二根蜡烛(指数1)是(2017.02.07 21:00),而且CurrDayBegin应该是1小时图中当前一天的第一根蜡烛,被iBarShift精确计算为(2017.02.08 06:00)。

CurrDayBegin = iTime(NULL, PERIOD_D1, 0);
      
while(TimeDayOfWeek(iTime(NULL, PERIOD_H1, iBarShift(NULL, PERIOD_H1, CurrDayBegin))) != TimeDayOfWeek(TimeCurrent()))

     // If iBarShift can't find the 0am candle and returns the 11pm candle of prev day.

  CurrDayBegin = CurrDayBegin + 3600;        // Move 1h until you find the 1st candle of today.                                        

2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: == 本周的其他日子 ==。
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayEnd = 1 (2017.02.07 21:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PrevDayBegin = 22 (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR CurrDayBegin = (2017.02.08 06:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [0] = (2017.02.08 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [1] = (2017.02.07 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR PERIOD_D1 [2] = (2017.02.06 00:00)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR Day of week = 3
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iHighest (Candle = 8) (Price = 2299.33) (Time = 2017.02.07 14:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: PDR iLowest (Candle = 19) (Price = 2288.57) (Time = 2017.02.07 03:00:001)
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Fib from Time1=2017.02.07 03:00 Price1=2288.57 to Time2=2017.02.07 14:00 Price2=2299.33
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend1 131296489639296384' from Time1=2017.02.08 06:00 Price1=2288.57 to Time2=2017.02.09 06:00 Price2=2288.57
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend2 131296489639296384' from Time1=2017.02.08 06:00 Price1=2293.95 to Time2=2017.02.09 06:00 Price2=2293.95
2017.02.08 06:53:53.252 Prev_Day_Range_LRT_50_v0.6 SPX500,H1: Trendline 'PDRTrend3 131296489639296384' from Time1=2017.02.08 06:00 Price1=2299.33 to Time2=2017.02.09 06:00 Price2=2299.33

那么,简而言之,是否有一种方法可以测试是否已经在图表上加载了所有的历史数据?或者我的代码中缺少一些东西?

谢谢你对我这篇很长的信息的理解。

如果你想看整个代码和日志,请让我知道。我不想在这里附上代码,但我很乐意私下发送。

这些是该指标的截图。

(1)使用不完整的历史计算(请注意横线不是从一天的开始)。

用不完整的历史计算的指标

(2) 使用完整的历史记录重新计算(水平线从一天的开始开始)。

使用全部历史数据重新计算的指标

Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
Problems with ERR_HISTORY_WILL_UPDATED (4066 ) & weekends
  • www.mql5.com
Hi i m building a custom indicator and got problems with the 4066 Error...