English Русский Español Deutsch 日本語 Português
将指标代码转移至 Expert Advisor 代码。指标结构

将指标代码转移至 Expert Advisor 代码。指标结构

MetaTrader 4示例 | 25 二月 2016, 15:56
1 290 0
Nikolay Kositsin
Nikolay Kositsin

简介

为了更好地理解作者的意图,推荐阅读以下材料:
  1. MetaQuotes Software Corp. 创建自定义指标的特点 (Features of Custom Indicators Creation)。https://www.mql5.com/zh/articles/1497
  2. Nikolay Kositsin.在一些指标中多次重新计算空柱 (Multiple Null Bar Re-Count in Some Indicators)。https://www.mql5.com/zh/articles/1411

在讨论本文标题中指示的主题之前,我们最好还是先来看看以下问题:“如果在大多数情况下,使用自定义指标运行的 EA 看起来比其他类似程序更简单易用,自定义指标自身的代码中包含了执行操作的所有必要项目,那么为什么我们还要将指标代码转移到 EA 代码中?特别是我们还考虑到一个事实,即如果代码编写正确,两种情况下的结果将完全相同!”

我认为,在两种情况下这种转移是必要的:

  1. 如果在 EA 计算中,根本没有用到在零柱上计算出的值,我们自然会想要忽略在零柱和第一根柱上的不必要的重新计算。这可将此类 EA 优化所需的时间缩短三倍,对于非常复杂并要占用大量资源的代码来说是相当有用的!
  2. Expert Advisor 用作商业用途时可最大程度防止代码被反编译。

在第二种情况下,显而易见,代码转移是相当合理的。在第一种情况下,大多数时候重新编写自定义指标的代码是很轻松的,无需进行不必要的计算!此类指标自然仅适用于 Expert Advisor,不适用于交易!那么,让我们从此类问题解决方案着手,开始讨论吧。


指标优化示例

首先,请注意一个自定义指标的以下代码片段:

int start()
  {
    int limit;
    int counted_bars = IndicatorCounted();
//---- the last calculated bar will be recalculated
    if(counted_bars > 0) 
        counted_bars--;
    limit = Bars - counted_bars - 1;
//---- the main cycle
    for(int i = limit; i >= 0; i--)
      {
        //---- 
        ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, 
                               PRICE_MEDIAN, i);
        ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, 
                              PRICE_MEDIAN, i);
        ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, 
                               PRICE_MEDIAN, i);
      }
//----
     return(0);
  }

在这种情况下,下面这一行对我们很重要:

if(counted_bars > 0) 
    counted_bars--;

确认变量 'counted_bars' 值减小 1 的意义在于:如果某自定义指标不包括此行,则当零柱更改时,该自定义指标可能会将错误的值从其缓冲区发送到 EA 中。EA 中的指标曲线看起来会相当“扭曲”。

在自定义指标中,变量 'limit' 和 'counted_bars' 可能会使用不同的名称,但程序代码必须执行这些检查!我认为这一解释足以澄清一些 EA 编写者的说法,即在 MetaTrader 中,指标缓冲区中的数据与从自定义指标中收到的同一数据并不是完全相同的。如果一个指标代码和 EA 代码编写正确,无论这个指标代码有多复杂艰涩,数据始终都是相同的!

但这里要注意的是,一些平滑算法对最开始进行平滑处理的基准点十分敏感。即,为了获得相同的值,指标的周期与 EA 中指标代码的周期中,最早的柱(所有柱都从其开始重新计算)的数量应是一致的。


这里有个示例,说明了为实现指标代码在 EA 中的更快操作而采取的这种优化方式。在主要指标周期中,将 0 更改为 1,之后指标停止重新计算其在零柱上的值。

// instead of
for(int i = limit; i >= 0; i--)      
// write
for(int i = limit; i >= 1; i--)

结果,源代码将如下所示:

int start()
  {
    int limit;
    int counted_bars = IndicatorCounted();
//---- the last bar will be recalculated
    if(counted_bars > 0) 
        counted_bars--;
    limit = Bars - counted_bars - 1;
      
  //---- the main cycle //now the cycle ends in 1
    for(int i = limit; i >= 1; i--)
      {
        //---- 
        ExtBlueBuffer[i] = iMA(NULL, 0, JawsPeriod, 0, MODE_SMMA, 
                               PRICE_MEDIAN, i);
        ExtRedBuffer[i] = iMA(NULL, 0, TeethPeriod, 0, MODE_SMMA, 
                              PRICE_MEDIAN, i);
        ExtLimeBuffer[i] = iMA(NULL, 0, LipsPeriod, 0, MODE_SMMA, 
                               PRICE_MEDIAN, i);
      }
  //----
    return(0);
  }
我再说一遍,上述方法仅供 EA 处理已关闭的柱,即除零柱外的所有柱。

如果您真的要在真金白银的实际交易中使用 EA,应仔细检查 Expert Advisor 中的所有细节以及 EA 使用的指标。此外,这些工作都应亲力亲为!我认为花几天时间彻底理解指标结构及其代码的优化方式,比起用三个月时间耐心地使用一个从草草编写的指标中获取值的 EA,会更加轻松也更为明智。

因此,必须清楚的是,将指标代码转移到 EA 代码中需要确切的理由。如果指标编写正确,即使未转移,EA 的操作也不会慢太多。使用自定义指标先编写一个 EA 代码,然后在此表格中进行检查,这样会比较容易。如果 EA 确实表现出完美的结果,可进一步优化代码,将自定义指标的调用逐个转变为指标代码片段。

必须注意,更改 EA 代码之后,不应再修改测试的损失值和利润值!

现有指标数量庞大,其中每个指标都有其独特的代码。这就是很难创建一个适用于所有指标的通用代码转移方式的原因。而还有一种情况会加剧这一问题,即同一个自定义指标可能在 EA 代码中多次出现。如果一个指标代码还算简单,可以将其写入自定义函数,并且在这种情况下将自定义指标转换为函数是相当简单的。但更常见的情况是 EA 代码繁杂庞大,几乎无法检测到其中的错误。我们所有的努力都徒劳无益。


指标结构的总体方案


在详细讨论本文的主题之前,让我们先从程序员的角度分析一下某个指标结构,该指标将成为某个 EA 代码的一部分。
//+------------------------------------------------------------------+
//|                                                IndicatorPlan.mq4 |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2007, MetaQuotes Software Corp."
#property link      "https://www.metaquotes.net/"
//---- drawing the indicator in the main window
#property indicator_chart_window 
//---- number of indicator buffers
#property indicator_buffers 1 
//---- indicator color
#property indicator_color1 Gold
//---- INPUT PARAMETERS OF THE INDICATOR
extern int period0 = 15;
extern int period1 = 15;
extern int period2 = 15;
//---- indicator buffers
double Ind_Buffer0[];
double Ind_Buffer1[];
double Ind_Buffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- defining the graph execution style
   SetIndexStyle(0, DRAW_LINE); 
//---- 3 indicator buffers are used for calculation
   IndicatorBuffers(3);
   SetIndexBuffer(0, Ind_Buffer0); 
   SetIndexBuffer(1, Ind_Buffer1);
   SetIndexBuffer(2, Ind_Buffer2);
//---- end of initialization
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
//---- Checking whether the bars number is enough for further calculation
   if(Bars < period0 + period1 + period2)
       return(0);
//----+ Insertion of variables with a floating point
   double Resalt0, Resalt1, Resalt2;
//----+ Insertion of integer variables and getting calculated bars
   int limit, MaxBar,bar, counted_bars = IndicatorCounted();
//---- checking for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last calculated bar must be recalculated 
   if(counted_bars > 0) 
       counted_bars--;
//---- defining the number of the oldest bar, 
// starting from which new bars will be recalculated
   limit = Bars - counted_bars - 1; 
//---- defining the number of the oldest bar, 
// starting from which new bars will be recalculated
   MaxBar = Bars - 1 - (period0 + period1 + period2); 
//---- initialization of zero 
   if(limit > MaxBar)
     {
       limit = MaxBar;
       for(bar = Bars - 1; bar >= MaxBar; bar--)
         {
           Ind_Buffer0[bar] = 0.0;
           Ind_Buffer1[bar] = 0.0;
           Ind_Buffer2[bar] = 0.0;
         }
     }
//----+ THE FIRST CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt1 calculation based on the external 
       // variable period1
       Ind_Buffer1[bar] = Resalt1;
     }
//----+ THE SECOND CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt2 calculation 
       // based on the values of the buffer Ind_Buffer1[]  
       // and external variable period2
       Ind_Buffer2[bar] = Resalt2;
     }
//----+ THE MAIN CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt0 calculation 
       // based on the values of the buffer Ind_Buffer2[]  
       // and external variable0
       Ind_Buffer0[bar] = Resalt0;
     }
   return(0);
  }
//+------------------------------------------------------------------+

当然,实际的指标在计算中可能会有不同数量的反射指标值、不同数量的指标缓冲区和不同数量的指标缓冲区值计算周期,但这并不会改变给定方案的意义。其他情况下也都是完全类似的。

现在让我们从方案元素中排除此上下文中对我们没有意义且在 Expert Advisor 中不必要的元素。

//+------------------------------------------------------------------+
//|                                               IndicatorPlan1.mq4 |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
//---- INPUT PARAMETERS OF THE INDICATOR
extern int period0 = 15;
extern int period1 = 15;
extern int period2 = 15;
//---- indicator buffers
double Ind_Buffer0[];
double Ind_Buffer1[];
double Ind_Buffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- end of initialization
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
//---- Checking whether the bars number is enough for further calculation
   if(Bars < period0 + period1 + period2)
       return(0);
//----+ Insertion of variables with a floating point
   double Resalt0, Resalt1, Resalt2;
//----+ Insertion of integer variables and getting calculated bars
   int limit, MaxBar, bar, counted_bars = IndicatorCounted();
//---- checking for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last calculated bar must be recalculated 
   if(counted_bars > 0) 
       counted_bars--;
//---- defining the number of the oldest bar, 
// starting from which new bars will be recalculated
   limit = Bars - counted_bars - 1; 
//---- defining the number of the oldest bar, 
// starting from which new bars will be recalculated
   MaxBar = Bars - 1 - (period0 + period1 + period2); 
//---- initialization of zero 
   if(limit > MaxBar)
     {
       limit = MaxBar;
       for(bar = Bars - 1; bar >= MaxBar; bar--)
         {
           Ind_Buffer0[bar] = 0.0;
           Ind_Buffer1[bar] = 0.0;
           Ind_Buffer2[bar] = 0.0;
         }
     }
//----+ THE FIRST CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt1 calculation  
       // based on the external variable period1
       Ind_Buffer1[bar]= Resalt1;
     }
//----+ THE SECOND CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt2 calculation 
       // based on the values of the buffer Ind_Buffer1[]  
       // and external variable period2
       Ind_Buffer2[bar] = Resalt2;
     }
//----+ THE MAIN CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt0 
       // based on the values of the buffer Ind_Buffer2[]  
       // and external variable period0
       Ind_Buffer0[bar] = Resalt0;
     }
   return(0);
  }
//+------------------------------------------------------------------+

只要不出现以下几个令人遗憾的小失误,此代码可以轻松放到 Expert Advisor 代码中:

  1. 首先请别忘了,函数 IndicatorCounted() 在 Expert Advisor 中不起作用!
  2. 我们也无法在初始化块中将自定义数组转变为指标数组!

因此,为了充分保护指标代码,我们首先要开发一个类似于函数 IndicatorCounted() 的函数,并通过某种方式在 Expert Advisor 中模拟指标缓冲区的类似项。遗憾的是,用标准函数在 EA 中直接模拟指标缓冲区不可行。目前为止,还没有适用于 Expert Advisor 的函数 SetIndexBuffer() 和 IndicatorBuffers() 的类似项!所以必须通过其他方法解决这个问题。此外,MQL4 中有足够的相关选项。


在 Expert Advisor 中模拟指标缓冲区

首先我们来详细地看一下指标缓冲区中执行的流程。

  1. 当一个指标连接到图表,且终端正常工作时,分配给指标缓冲区变量的值在周期之间不会丢失。
  2. 如果图表上的零柱(最后一个柱)有更改,该指标缓冲区的所有元素都会被转移。
  3. 如果新增了一个柱,指标中的变量限值将从 1 变为 2,且所有缓冲区元素移一位,即零柱变成第一个柱,第一个变为第二个,以此类推。
  4. 指标缓冲区的维数会自然而然地发生变化。如果下一价格变动时柱未发生变化,所有缓冲区元素都原地不动。

现在开始模拟指标缓冲区。为实现这一目的,我们将使用以下 MQL4 标准函数:ArraySize()、ArrayResize() 和 ArraySetAsSeries()。指标缓冲区模拟的代码相当简单,其工作原理如下:当零柱发生变化时,将还原缓冲区中元素定义的正向顺序,并使用函数 ArrayResize() 从新柱将新单元添加到缓冲区,之后以反向顺序安排缓冲区中元素定义,且空白单元显示在模拟指标缓冲区中的第一批单元内。

//---- INDICATOR BUFFERS EMULATION
  int NewSize = iBars(symbol, timeframe);
  //----  Checking the change of the zero bar
  if(ArraySize(Ind_Buffer0) < NewSize)
    {
      //---- Set the direct indexing direction in the array 
      ArraySetAsSeries(Ind_Buffer0, false);
      ArraySetAsSeries(Ind_Buffer1, false);
      ArraySetAsSeries(Ind_Buffer2, false);
      //---- Change the size of the emulated indicator buffers 
      ArrayResize(Ind_Buffer0, NewSize); 
      ArrayResize(Ind_Buffer1, NewSize); 
      ArrayResize(Ind_Buffer2, NewSize); 
      //---- Set the reverse indexing direction in the array 
      ArraySetAsSeries(Ind_Buffer0, true);
      ArraySetAsSeries(Ind_Buffer1, true);
      ArraySetAsSeries(Ind_Buffer2, true); 
    } 
//----


顺便提一下,当八个指标缓冲区不足以执行中间计算时,这种指标缓冲区模拟方法也适用于指标。随附文件 SMI.mq4 和 SMI_New.mq4 有相关示例。




替代函数 IndicatorCounted()

现在我们来分析函数 IndicatorCounted() 的模拟。此函数返回上一次指标调用之后,当前图表中未发生变化的柱数。也可以换句话说。此函数返回上一价格变动时客户终端中可用的当前图表柱的数量。对于完全相同的值,我们需要将计算得出的柱数减去 1。因此,可以用一个静态整数变量轻松取代此函数,在从预定义变量 Bars-1 中获取一个值之后,该静态整数变量将使用此值进行初始化。之后,指标方案将使用以下形式:
//+------------------------------------------------------------------+
//|                                            NewIndicatorPlan1.mqh |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
 
//---- INPUT INDICATOR PARAMETERS
extern int period0 = 15;
extern int period1 = 15;
extern int period2 = 15;
//---- indicator buffers
double Ind_Buffer0[];
double Ind_Buffer1[];
double Ind_Buffer2[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- initialization end
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
//---- Checking whether the bars number is enough for further calculation
   if(Bars < period0 + period1 + period2)
       return(0);
//---- INDICATOR BUFFERS EMULATION
   if(ArraySize(Ind_Buffer0) < Bars)
     {
       ArraySetAsSeries(Ind_Buffer0, false);
       ArraySetAsSeries(Ind_Buffer1, false);
       ArraySetAsSeries(Ind_Buffer2, false);
       //----  
       ArrayResize(Ind_Buffer0, Bars); 
       ArrayResize(Ind_Buffer1, Bars); 
       ArrayResize(Ind_Buffer2, Bars); 
       //----
       ArraySetAsSeries(Ind_Buffer0, true);
       ArraySetAsSeries(Ind_Buffer1, true);
       ArraySetAsSeries(Ind_Buffer2, true); 
     } 
//----+ INSERTION OF A STATIC INTEGER MEMORY VARIABLE
   static int IndCounted;
//----+ Insertion of variables with a floating point
   double Resalt0, Resalt1, Resalt2;
//----+ Insertion of integer variables and getting calculated bars
   int limit, MaxBar, bar, counted_bars = IndCounted;
//---- checking for possible errors
   if(counted_bars < 0)
       return(-1);
//---- the last calculated bar must be recalculated 
   if(counted_bars > 0) 
       counted_bars--;
//----+ REMEMBERING THE AMOUNT OF ALL BARS OF THE CHART
   IndCounted = Bars - 1;
//---- defining the number of the oldest bar, 
//     starting from which new bars will be recalculated
   limit = Bars - counted_bars - 1; 
//---- defining the number of the oldest bar, 
//     starting from which new bars will be recalculated
   MaxBar = Bars - 1 - (period0 + period1 + period2); 
//---- initialization of zero 
   if(limit > MaxBar)
     {
       limit = MaxBar;
       for(bar = Bars - 1; bar >= 0; bar--)
         {
           Ind_Buffer0[bar] = 0.0;
           Ind_Buffer1[bar] = 0.0;
           Ind_Buffer2[bar] = 0.0;
         }
     }
//----+ THE FIRST CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt1 calculation  
       // based on the external variable period1
       Ind_Buffer1[bar] = Resalt1;
     }
//----+ THE SECOND CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt2 calculation 
       // based on the values of the buffer Ind_Buffer1[] and external variable period2
       Ind_Buffer2[bar] = Resalt2;
     }
//----+ THE MAIN CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt0 calculation 
       // based on the values of the buffer Ind_Buffer2[] and external variable period0
       Ind_Buffer0[bar] = Resalt0;
     }
   return(0);
  }
//+------------------------------------------------------------------+

指标代码的进一步转换及其结构的最终方案

当然,假如某个 Expert Advisor 中需要在当前图表上使用此指标,且仅需使用一次,我们可以仅将指标代码分批转移到 EA 代码中!如果这个指标要使用两次,我们只需在第二个用例中更改所有指标变量的名称,然后再次添加此代码。但这样一来,Expert Advisor 将变得更加复杂。

处理其他时间范围内的数据也很简单。用类型的时间序列替代 Bars 类型的预定义变量

iBars(string symbol,  int timeframe);

NULL - for string symbol;, 0 (in timeseries) - for int timeframe;, Close[bar] - for

iClose(string symbol, int timeframe, bar);


等等。

现在我们来分析指标行:

//---- checking for possible errors
if(counted_bars < 0)
    return(-1);
//---- the last calculated bar must be recalculated 
if(counted_bars > 0) 
    counted_bars--;

对于我们的指标结构类型中提供的函数 IndicatorCounted() 的替代项,指标 counted_bars 绝不会小于 0。因此,Expert Advisor 中的这一行

//---- checking for possible errors
if(counted_bars < 0)
    return(-1);

可以省略。而下面两行:

//---- the last calculated bar must be recalculated 
if(counted_bars > 0) 
    counted_bars--;

是相同的。应该把这几行删去,它们只会对第一根柱进行不必要的重新计算,拖慢 EA 工作进度,并且在 EA 操作中,上述检查是毫无用处的。之后,要转移到 EA 中的最终代码如下所示:

//+------------------------------------------------------------------+
//|                                            NewIndicatorPlan2.mqh |
//|                      Copyright © 2007, MetaQuotes Software Corp. |
//|                                        https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
 
//---- INPUT INDICATOR PARAMETERS
extern int period0 = 15;
extern int period1 = 15;
extern int period2 = 15;
//---- indicator buffers
double Ind_Buffer0[];
double Ind_Buffer1[];
double Ind_Buffer2[];
//---- DECLARING VARIABLES FOR CHOOSING A CHART
string symbol; int timeframe;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
//---- CHOOSING A CHART FRO INDICATOR CALCULATION
   symbol = Symbol();//INITIALIZATION OF THE VARIABLE symbol;
   timeframe =240;//INITIALIZATION OF THE VARIABLE timeframe;
//---- end of initialization
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int start()
  {
// GETTING THE AMOUNT OF ALL BARS OF THE CHART
   int IBARS = iBars(symbol, timeframe);
//---- Checking whether the bars number is enough for further calculation
   if(IBARS < period0 + period1 + period2)
       return(0);
// INDICATOR BUFFERS EMULATION
   if(ArraySize(Ind_Buffer0) < IBARS)
     {
       ArraySetAsSeries(Ind_Buffer0, false);
       ArraySetAsSeries(Ind_Buffer1, false);
       ArraySetAsSeries(Ind_Buffer2, false);
       //----  
       ArrayResize(Ind_Buffer0, IBARS); 
       ArrayResize(Ind_Buffer1, IBARS); 
       ArrayResize(Ind_Buffer2, IBARS); 
       //----
       ArraySetAsSeries(Ind_Buffer0, true);
       ArraySetAsSeries(Ind_Buffer1, true);
       ArraySetAsSeries(Ind_Buffer2, true); 
     } 
// INSERTION OF A STATIC INTEGER MEMORY VARIABLE
   static int IndCounted;
//----+ Insertion of variables with a floating point
   double Resalt0, Resalt1, Resalt2;
//----+ Insertion of integer variables and GETTING ALREADY CALCULATED BARS
   int limit, MaxBar, bar, counted_bars = IndCounted;
//----+ REMEMBERING THE AMOUNT OF ALL BARS OF THE CHART
   IndCounted = IBARS - 1;
//---- defining the number of the oldest bar,   
//     starting from which new bars will be recalculated
   limit = IBARS - counted_bars - 1; 
//---- defining the number of the oldest bar, 
//     starting from which new bars will be recalculated
   MaxBar = IBARS - 1 - (period0 + period1 + period2); 
//---- initialization of zero 
   if(limit > MaxBar)
     {
       limit = MaxBar;
       for(bar = IBARS - 1; bar >= 0; bar--)
         {
           Ind_Buffer0[bar] = 0.0;
           Ind_Buffer1[bar] = 0.0;
           Ind_Buffer2[bar] = 0.0;
         }
     }
//----+ THE FIRST CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt1 calculation based on the external 
       // variable period1
       Ind_Buffer1[bar] = Resalt1;
     }
//----+ THE SECOND CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt2 calculation  
       // based on the values of the buffer Ind_Buffer1[] and the external variable period2
       Ind_Buffer2[bar] = Resalt2;
     }
//----+ THE MAIN CYCLE OF INDICATOR CALCULATION 
   for(bar = limit; bar >= 0; bar--)
     {
       // Here code of the variable Resalt0 calculation 
       // based on the values of the buffer Ind_Buffer2[] and the external variable period0
       Ind_Buffer0[bar] = Resalt0;
     }
   return(0);
  }
//+------------------------------------------------------------------+

这里我们应该考虑到某个时刻。多次重新计算零柱时,在计算周期开始时的第一根柱上会看到指标,记住一些用于将代码返回其初始状态的变量的值(文章)。在 Expert Advisor 中删除最后两行后,按上述方式,针对零柱(而不再是第一根柱)记住相关值。在计算周期开始时,此类指标通常包含以下代码片段:

// Saving the variables values
if(bar == 1)
    if(((limit == 1) && (time == Time[2])) || (limit > 1))
      {
        time = Time[2];
        // These variables are not interesting for us
        PRICE = price;
        TREND = trend;
        RESALT = Resalt;
      }
//+------------------------------------------------------------------+

应修改此代码片段,以保存零柱而非第一根柱上的变量值。所有“1”都应替换为“0”,所有“2”替换为“1”。如果此代码不是为在当前图表中使用而准备的,则还应更改时间序列数组的参考,即将

time = Time[1];

更改为

time = iTime(symbol, timeframe, 1);

结果,更改后的代码片段如下所示:

// Saving variables values
if(bar == 0)
    if(((limit == 0) && (time == iTime(symbol, timeframe, 1))) || (limit > 0))
      {
        time = iTime(symbol, timeframe, 1);
        PRICE = price;
        TREND = trend;
        RESALT = Resalt;
      }
//+------------------------------------------------------------------+

指标代码也可包含本人自己开发的平滑函数,如 XXXSeries()。要在 EA 代码中使用带此类函数的代码片段,这些函数应替换为其 EA 类似函数。


总结

毫无疑问,目前给出的这种将指标代码转移到 EA 代码的算法还相当粗糙,不是最佳的算法,但文本的目的并不是细致地描述此流程的所有细节。本文的主要目的是一窥指标的概貌,并以最简化的形式分析代码转移的总体思路,而不是将重点放在次要的细节上。我认为我们已达成了这个目标!在下一篇文章中,我们将分析 Expert Advisor 的一般结构和指标函数的结构方案

本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/1456

附加的文件 |
IndicatorPlan1.mq4 (3.03 KB)
SMI.MQ4 (4.87 KB)
SMI_New.MQ4 (5.93 KB)
将指标代码转移至 Expert Advisor 代码。Expert Advisor 和指标函数的总体结构方案 将指标代码转移至 Expert Advisor 代码。Expert Advisor 和指标函数的总体结构方案
本文详细介绍将指标代码转移至 Expert Advisor 代码的方式,并详细介绍编写 Expert Advisor 的过程,在此过程中,不调用任何自定义指标,且整个程序代码用于计算 Expert Advisor 中的必要指标值。本文提供 Expert Advisor 更改的总体方案,以及基于自定义指标构建指标函数的想法。本文面向拥有使用 MQL4 语言进行编程的经验的读者。
日内交易中的时间转换原则 日内交易中的时间转换原则
本文包含了允许接收更加平稳的价格流的操作时间概念。也包含了带时间转换裕度的已更改移动平均线的代码。
终端服务客户端如何使掌上电脑成为台式机的朋友 终端服务客户端如何使掌上电脑成为台式机的朋友
本文描述了通过 PDA 连接已安装 MT4 客户端的远程计算机。
使用 Skype 发送来自 Expert Advisor 的消息 使用 Skype 发送来自 Expert Advisor 的消息
本文介绍如何使用 Skype 将来自 Expert Advisor 的内部消息和短信发送给移动电话。