hefeiddd 发表于 2008-5-25 07:26

在一些指标中多次重新计算基础柱体 [ en | ru ]http://www.mql4.com/i/print.gif

在这篇文章中,我想讨论一下 MetaTrader 4 客户端中当基础柱体改变时多次重新计算指标值。它的核心问题是,你能够在网上找到许多好的指标,他们只对于历史数据运作正常,但当交易平台连接上服务器时,它们得出的结果,说得婉转一些,就是不能实现设置在这些指标中的运算规则!
通常,这些指标的作者,在斟酌了这个问题后,最终找到了一个简单但不聪明得解决方法:他们重新计算他们的指标图表中所有的柱体在每次运行 int start() 函数时的值,来得出最后那个基础柱体的值。
第一眼看上去所有问题好象都这样解决了,但是事实上,问题转移到了另一个范畴。这样的指标占用系统资源,结果会导致电脑死机。

为了解决这个问题,我们首先应该考虑指标被建立的一般思路。每个指标都是含有一些变量的函数:

Indicator = Function (Variable1, Variable2, Variable3, .... etc.).

所有的指标可以被分成两大类:

[*]第一类 - 这类指标的所有变量只使用安全价位和外部变量进行计算;对于任何柱体,这些变量的计算都不用考虑之前柱体的相应变量。[*]第二类 - 在这类指标中,至少有一个变量是通过之前柱体的相应变量计算而来的:

VariableN(i) = FunctionN(VariableN(i+1)),

左边的值根据第 i 个柱体而得,右边括号里的值根据第 i+1 个柱体而得。或者至少这个变量是通过先前柱体的另一个变量而计算初的:

VariableN(i) = FunctionR(VariableX(i+1)),

同样地,左边的值是根据第 i 个柱体而得,右边括号里的值根据第 i+1 个柱体而得。
我们对第二类指标感兴趣,因为它引出了上面的问题。指标在哪里需要在基础柱体上被多次重算,这些变量在逻辑上应该和另一些柱体开始对所有柱体多次重新计算的值一样,即使这个指标是用 IndicatorCounted() 函数只依靠对基础柱体重新计算而编制的。这种指标被证明对于实时行情是完全没用的。为了解释这些,让我们来看一下这个特殊的指标:


//+------------------------------------------------------------------+//|                                                         T3.mq4 |//|                                                         MojoFX |//| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ |//+------------------------------------------------------------------+#property copyright "MojoFX - Conversion only" #property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"//----#property indicator_chart_window#property indicator_buffers 1 #property indicator_color1 Red//----extern int MA_Period = 14;extern double b = 0.7; //----double MapBuffer[];double e1, e2, e3, e4, e5, e6; double c1, c2, c3, c4;double n, w1, w2, b2, b3; //+------------------------------------------------------------------+//| Custom indicator initialization function                         |//+------------------------------------------------------------------+int init(){    SetIndexStyle(0, DRAW_LINE);    IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));    IndicatorShortName("T3" + MA_Period);    SetIndexBuffer(0, MapBuffer);    b2 = b * b;    b3 = b2 * b;    c1 = -b3;    c2 = (3 * (b2 + b3));    c3 = -3 * (2 * b2 + b + b3);    c4 = (1 + 3 * b + b3 + 3 * b2);    n = MA_Period;    if(n < 1)         n=1;    n = 1 + 0.5 * (n - 1);    w1 = 2 / (n + 1);    w2 = 1 - w1;    //----   return(0);}//+------------------------------------------------------------------+//| Custom indicator iteration function                              |//+------------------------------------------------------------------+int start()   {    // In this case, indicator's values are fully recalculated   // on all bars at every launch of the start() function    for(int bar = Bars-1; bar >= 0; bar--)   /*          If the line named "for(int bar=Bars-1; bar>=0; bar--)" is replaced with the four lines below         for recounting of the indicator on only last bars         at each launch of the start() function, this indicator will work properly         only on historical data:          intlimit,counted_bars=IndicatorCounted();         if(counted_bars>0) counted_bars--;         limit=Bars-1-counted_bars;         for(int bar=limit; bar>=0; bar--)         */      {      // Variables e1,e2,e3,e4,e5,e6 are functions of themselves         // calculated on the preceding bar          e1 = w1 * Close + w2 * e1;      e2 = w1 * e1 + w2 * e2;      e3 = w1 * e2 + w2 * e3;      e4 = w1 * e3 + w2 * e4;      e5 = w1 * e4 + w2 * e5;      e6 = w1 * e5 + w2 * e6;         MapBuffer=c1 * e6 + c2 * e5 + c3 * e4 + c4 * e3;      }   //----    return(0);}//+------------------------------------------------------------------+

在这个案例中,最简单的解决方法是用我曾经在指标代码中提到过的数组来代替变量:

//+------------------------------------------------------------------+//| T3.mq4                                                         |//| MojoFX                                                         |//| http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/ |//+------------------------------------------------------------------+#property copyright "MojoFX - Conversion only" #property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"#property indicator_chart_window#property indicator_buffers 1#property indicator_color1 Red extern int T3_Period = 14;extern double b = 0.7; double MapBuffer[];//---- Turning of variables into buffersdouble e1[], e2[], e3[], e4[], e5[], e6[]; //----double c1, c2, c3, c4;double n, w1, w2, b2, b3; //+------------------------------------------------------------------+//| Custom indicator initialization function                         |//+------------------------------------------------------------------+int init(){//----    SetIndexStyle(0, DRAW_LINE);    IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));   IndicatorShortName("T3" + T3_Period);    SetIndexBuffer(0, MapBuffer);//---- Writing of variables into indicator buffers   IndicatorBuffers(7);    SetIndexBuffer(1, e1);   SetIndexBuffer(2, e2);   SetIndexBuffer(3, e3);    SetIndexBuffer(4, e4);   SetIndexBuffer(5, e5);   SetIndexBuffer(6, e6); //----   b2=b*b;   b3=b2*b;   c1=-b3;    c2=(3*(b2+b3));   c3=-3*(2*b2+b+b3);    c4=(1+3*b+b3+3*b2);    n=T3_Period;   if (n<1) n=1;    n = 1 + 0.5*(n-1);   w1 = 2 / (n + 1);    w2 = 1 - w1;//----   return(0);   }//+-----------------------------------------------------------------------+//| Custom indicator iteration function                                 |//+-----------------------------------------------------------------------+int start(){ //----+ check whether the amount of bars is sufficient for correct //      calculation of the indicator   if(Bars - 1 < T3_Period)       return(0); //----+ Entering of integer variables and obtaining of bars already counted   int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors   if(counted_bars < 0)       return(-1);//---- the last counted bar must be re-counted    if(counted_bars > 0)      counted_bars--;//---- determining of the oldest bar number, starting from which//   all bars will be re-counted   MaxBar = Bars - 1 - T3_Period; //---- determining of the oldest bar number, starting from which//   only new bars will be re-counted   limit = (Bars - 1 - counted_bars); //---- initialization of null   if(limit > MaxBar)   {       for(int bar = Bars - 1; bar >= limit; bar--)            MapBuffer = 0.0;       limit = MaxBar;      }//+--- basic loop of indicator calculation    for(bar = limit; bar >= 0; bar--)   {         e1 = w1*Close + w2*e1;       e2 = w1*e1 + w2*e2;       e3 = w1*e2 + w2*e3;       e4 = w1*e3 + w2*e4;       e5 = w1*e4 + w2*e5;       e6 = w1*e5 + w2*e6;       MapBuffer = c1*e6 + c2*e5 + c3*e4 + c4*e3;   }//+--- termination of the basic loop   return(0);}//+----------------------------------------------------------------+
问题被解决了,但既然这样,这是解决特殊问题的特殊办法:这样会有非常多的变量,这也是为什么决不能把所有的变量都放入指标缓冲区。在这种情况下,通常的解决方法都是这样的,为了正常地多次重算指标值,我们只需要依靠第二个柱体来计算出的指标而获得的变量值,而这不但是重新计算最终值,也是重新计算只有一个柱体的最终值的更好的更广泛的方法!

因此,在第二个柱体循环结束时的那些变量值必须被存储在那些并不包含在指标的任一程序块中的用来存储的变量里,也就是那些在指标代码开头被定义的变量。这些存储变量可以被编入初学者的文章,在 int start() 函数里介绍。当指标计算循环钱每次运行 start() 函数时,如果被计算的柱体之一不等于零(if (IndicatorCounted()!=0),从存储变量中提取值赋予当前的指标变量。这此之后,没有计算过的柱体可以当作开始时那样,被同样的代码进行计算!大家最好记住这些变量不是在第二个柱体的循环结束时,而是在第一个柱体的开始处。这是我们在更复杂的例子中要做的!下面是用这种思路编写的同样的指标:

//+-------------------------------------------------------------------------+//|                                                         T3.mq4      |//|                              Copyright2005,            MojoFX         | //|http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators      | //+-------------------------------------------------------------------------+ #property copyright "MojoFX - Conversion only"#property link "http://groups.yahoo.com/group/MetaTrader_Experts_and_Indicators/"#property indicator_chart_window #property indicator_buffers1#property indicator_color1Yellow //---- extern intT3_Period = 8;   extern double b = 0.7;//---- //---- double MapBuffer[]; //----double e1, e2, e3, e4, e5, e6; double n, c1, c2, c3, c4, w1, w2, b2, b3; //---- introduction of variables to save variables e1,e2,e3,e4,e5,e6int time2; double E1, E2, E3, E4, E5, E6; //+--------------------------------------------------------------------------+ //|T3 initialization function                                              |//+--------------------------------------------------------------------------+int init(){//---- indicators setting   SetIndexStyle(0, DRAW_LINE);    IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS));   IndicatorShortName("T3" + T3_Period);    SetIndexBuffer(0, MapBuffer);   b2 = b*b;    b3 = b2*b;   c1 = -b3;   c2 = (3*(b2 + b3));    c3 = -3*(2*b2 + b + b3);   c4 = (1 + 3*b + b3 + 3*b2);    if(T3_Period < 1)      T3_Period = 1;   n = 1 + 0.5*(T3_Period - 1);    w1 = 2 / (n + 1);   w2 = 1 - w1; //---- initialization complete   return(0);}//+---------------------------------------------------------------------------+//| T3 iteration function                                                   |//+---------------------------------------------------------------------------+ int start(){//----+ check whether the amount of bars is enough for correct //      indicator calculation   if(Bars-1 < T3_Period)       return(0); //----+ introduction of integer variables and getting of bars already counted   int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors   if(counted_bars < 0)       return(-1); //---- the last counted bar must be re-counted   if(counted_bars > 0)      counted_bars--;//---- determining of the oldest bar number, starting from which //   all bars will be re-counted   MaxBar = Bars - 1 - T3_Period; //---- determining of the oldest bar number, starting from which //   only new bars will be re-counted   limit = (Bars - 1 - counted_bars);//---- initialization of null    if(limit > MaxBar)   {       for(int bar = Bars - 1; bar >= MaxBar; bar--)            MapBuffer = 0.0;       limit = MaxBar;      } //+--- before the basic loop of indicator calculation, restore values//   of variables as they were after counting on the second bar//+--- restore values of the variables +=======+   int Tnew = Time;    if(limit < MaxBar)   if(Tnew == time2)      {       e1 = E1;      e2 = E2;         e3 = E3;      e4 = E4;      e5 = E5;         e6 = E6;       }   else      {       if(Tnew > time2)         Print("ERROR01");       else            Print("ERROR02");       return(-1);   } //+--- +==========================================+//+--- Basic loop to calculate the indicator   for(bar = limit; bar >= 0; bar--)      {       //+--- Memorize values of variables as they were after      //   the second bar       //+--- Save values of the variables +=============+      if(bar == 1)            if(((limit == 1)&&(time2 != Time)) || (limit > 1))            {               time2 = Time;               E1 = e1;               E2 = e2;                E3 = e3;                E4 = e4;                E5 = e5;               E6 = e6;            }       //+---+============================================+       e1 = w1*Close + w2*e1;      e2 = w1*e1 + w2*e2;       e3 = w1*e2 + w2*e3;       e4 = w1*e3 + w2*e4;       e5 = w1*e4 + w2*e5;       e6 = w1*e5 + w2*e6;       MapBuffer=c1*e6 + c2*e5 + c3*e4 + c4*e3;   }   //+--- terminate the basic loop   return(0);}//+-----------------------------------------------------------------+
和前面的比较,这个指标需要更少的信息存储在内存中的变量里。但它看上去比前一个更复杂!
下面这段代码是同一个指标的,使用了 int start() 函数,提供给能够将智能交易程序和代码结合的高级开发者。在这段代码里,智能交易程序只在基础柱体上计算指标。当然代码里的这个变量只适合作为历史数据的测试程序。对于智能交易程序的在线运作,我们不得不使用另一个代码里的变量,来自于我们在最后的例子中研究的指标。假设,如果一个新的基础柱体开始形成,在第一个柱体上的指标值完全被计算出并且不应该被重新计算。同样也适用于柱体变化时被储存的变量。这里需要强调,如果这样一段复杂的代码没有写入智能交易程序,就不可能明白这样的程序怎么样进行计算,在什么基础上来进行交易!如果代替这段代码,用被证实的变量,每个价位都在所有的柱体上重新进行计算指标,最后得出基础柱体,我们可能用一个月的时间来等结果!

int start(){//----+ check whether the amount of bars is enough for correct //      indicator calculation   if(Bars-1 < T3_Period)       return(0);//---- determine the oldest bar number, starting from which //   all bars will be re-counted   int MaxBar = Bars - 1 - T3_Period;//---- initialization of null   if(MaxBar = 0)       for(int bar = Bars - 1; bar > 0; bar--)         MapBuffer = 0.0;//+--- before basic indicator calculation, restore values //   of variables as they were after calculation on the first bar//+--- restoring values of variables +=======+   int Tnew0 = Time;   int Tnew1 = Time;   if(Tnew0 == time2)   {       e1 = E1;      e2 = E2;      e3 = E3;      e4 = E4;      e5 = E5;      e6 = E6;       }   else      if(Tnew1 != time2)         {         if(Tnew1 > time2)               Print("ERROR01");         else                Print("ERROR02");         return(-1);         }//+--- +==============================================+//+--- Memorize values of variables as they were after //   the first bar//+--- Saving of values of variables +================+    if(Tnew0 != time2)   {       time2 = Tnew0;       E1 = e1;      E2 = e2;      E3 = e3;      E4 = e4;      E5 = e5;      E6 = e6;   }//+---+============================================+ //+--- indicator calculation (calculation is made always //   only on the null bar)   e1 = w1*Close + w2*e1;   e2 = w1*e1 + w2*e2;   e3 = w1*e2 + w2*e3;   e4 = w1*e3 + w2*e4;   e5 = w1*e4 + w2*e5;   e6 = w1*e5 + w2*e6;   MapBuffer = c1*e6 + c2*e5 + c3*e4 + c4*e3;//----+ ------------------------------------------------+//----+ The code of your expert must be placed here   |//----+ ------------------------------------------------+   return(0);}//+----------------------------------------------------------------+
当然,这段代码变得复杂了一些!
下面是个可仿效的指标,在这个指标里,为了运作正常,当运行 int start() 函数时,只有一个逻辑变量必须被储存。但是如果没有这个几乎不被察觉的变化,指标不能适当地运作:

//+------------------------------------------------------------------+//|                                                   3LineBreak.mq4 |//|                               Copyright 2004, Poul_Trade_Forum   |//|                                                         Aborigen |//+------------------------------------------------------------------+ #property indicator_chart_window #property indicator_buffers 2#property indicator_color1 Gold#property indicator_color2 Magenta //---- extern int Lines_Break = 3;//---- double HighBuffer[]; double LowBuffer [];//---- double VALUE1, VALUE2, Swing = 1, OLDSwing; //---- Introduction of variables for multiple re-count of bar int time2, SWING;//+---------------------------------------------------------------------+//| 3LineBreak initialization function                                  |//+---------------------------------------------------------------------+ int init()   {   //---- Chart is performed as a hystogram    SetIndexStyle(0, DRAW_HISTOGRAM);   SetIndexStyle(1, DRAW_HISTOGRAM); //---- 2 indicator buffers are used for counting.   SetIndexBuffer(0, HighBuffer);   SetIndexBuffer(1, LowBuffer ); //---- setting of indicator values that will not be visible on the chart   SetIndexEmptyValue(0, 0);   SetIndexEmptyValue(1, 0); //---- names for data windows and labels for subwindows.   IndicatorShortName("3LineBreak");   SetIndexLabel   (0, "3LineBreak"); //---- setting of the bar number, starting from which the indicator //   will be drawn   SetIndexDrawBegin(0, Lines_Break);   SetIndexDrawBegin(1, Lines_Break); //---- termination of the initialization   return(0);}//+------------------------------------------------------------------+//| 3LineBreak iteration function                                    |//+------------------------------------------------------------------+ int start()   {//----+ Introduction of integer variables and getting of bars already counted   int MaxBar, limit, counted_bars = IndicatorCounted(); //---- check for possible errors   if(counted_bars < 0)       return(-1);//---- the last counted bar must be re-counted )    if(counted_bars > 0)      counted_bars--;//---- determining of the oldest bar number, starting from which //   all bars will be re-counted   MaxBar = Bars - 1 - Lines_Break; //---- determining of the oldest bar number, starting from which //   only new bars will be re-counted   limit = (Bars - 1 - counted_bars); //---- initialization of null   if(limit > MaxBar)   {       for(int bar = limit; bar > MaxBar; bar--)          {            HighBuffer = 0.0;            LowBuffer = 0.0;          }      limit=MaxBar;   }//----//+--- restoring of values of variables +================+   int Tnew = Time;    if(limit < MaxBar)   if(Tnew == time2)       Swing = SWING;    else      {       if(Tnew > time2)         Print("ERROR01");       else             Print("ERROR02");       return(-1);       } //+--- +==================================================+//+--- basic loop of indicator calculation   for(bar = limit; bar >= 0; bar--)      {       //+--- Saving of values of variables +=============+      if(bar == 1)         if(((limit == 1) && (time2 != Time))||(limit > 1))            {               time2 = Time;               SWING = Swing;             }      //+---+============================================+       OLDSwing = Swing;       //----       VALUE1 = High;       VALUE2 = Low;       //----      if(OLDSwing == 1 &&Low < VALUE2)            Swing = -1;       if(OLDSwing == -1 &&High > VALUE1)            Swing = 1;       //----      if(Swing == 1)         {            HighBuffer = High;            LowBuffer = Low ;          }      if(Swing == -1)         {            LowBuffer = High;            HighBuffer = Low;          }      } //+--- termination of the basic loop   return(0);}
下面是类似的情况:
//+------------------------------------------------------------------+//|                                                BrainTrend1.mq4 |//|                                     BrainTrading Inc. System 7.0 |//|                                     http://www.braintrading.com|//+------------------------------------------------------------------+#property copyright "BrainTrading Inc. System 7.0" #property link      "http://www.braintrading.com"#property indicator_chart_window#property indicator_buffers 2#property indicator_color1 Red #property indicator_color2 Lime//---- double Ind_Buffer1[];double Ind_Buffer2[];double value2, Range, val1, val2, d, val3; int    f, p, x1, x2, value11;//+------------------------------------------------------------------+//| BrainTrend1 initialization function                              |//+------------------------------------------------------------------+int init(){//----    SetIndexStyle(0, DRAW_HISTOGRAM);   SetIndexBuffer(0, Ind_Buffer1); //----    SetIndexStyle(1, DRAW_HISTOGRAM);   SetIndexBuffer(1, Ind_Buffer2); //----      string short_name;   short_name = "BrainTrend1";   IndicatorShortName(short_name);   SetIndexLabel(0, "" + short_name + "_Down");   SetIndexLabel(1, "" + short_name + "_Up");   IndicatorDigits(MarketInfo(Symbol(), MODE_DIGITS)); //----   f = 7;    d = 2.3;   x1 = 53;    x2 = 47;    value11 = 9; //---- termination of the initialization   return(0);}//+------------------------------------------------------------------+//| BrainTrend1 iteration function                                 |//+------------------------------------------------------------------+int start()   {//---- check whether the amount of bars is enough to calculate   if(Bars < 11)       return(0); //---- Introduction of statistical memory variables for multiple //   recalculation of the null bar    static int MEMORY, time2;//----+ Introduction of integer variables and getting of counted bars   int limit, MaxBar,bar, counted_bars = IndicatorCounted(); //---- check for possible errors   if(counted_bars < 0)       return(-1);//---- the last counted bar must be re-counted   if(counted_bars > 0)      counted_bars--;//---- determining of the oldest bar number, starting from which //   all bars will be re-counted   MaxBar = Bars - 1 - 10; //---- determining of the oldest bar number, starting from which //   only new bars will be re-counted   limit = Bars - counted_bars - 1;    if(limit > MaxBar)    limit = MaxBar;   Comment("BrainTrading Inc. System 7.0");//+--- restoring of values of variables +================+   int Tnew = Time;    if(limit < MaxBar)   if(Tnew == time2)      p=MEMORY;    else   {       if(Tnew > time2)         Print("ERROR01");       else             Print("ERROR02");       return(-1);       }//+--- +===================================================+    bar = limit;   while(bar >= 0)   {      //+--- Saving of values of variables         +====+      if(bar == 1)         if(((limit == 1) && (time2 != Time)) || (limit > 1))            {               time2 = Time;               MEMORY = p;             }      //+---+====================================+       Range = iATR(NULL, 0, f, bar) / d;       value2 = iStochastic(NULL, 0, value11, value11, 1, 0, 0, 0, bar);       val1 = 0.0;       val2 = 0.0;       val3 = MathAbs(Close - Close);       if(value2 < x2 && val3 > Range)            p = 1;       if(value2 > x1 && val3 > Range)            p = 2;       if(value2 < x2 && (p == 1||p == 0))          {         if(val3 > Range)             {                val1 = High;               val2 = Low ;             }          }       if(value2 > x1 && (p == 2||p == 0))          {         val2 = High;         val1 = Low ;         }      Ind_Buffer1 = val1;       Ind_Buffer2 = val2;            bar--;   }//+--- termination of the basic loop   return(0);}
为了让下面的指标运作正常,要重建的不仅是标准的变量,还有缓冲区:

//+------------------------------------------------------------------+//|                                                BrainTrend2.mq4 |//|                                     BrainTrading Inc. System 7.0 |//|                                     http://www.braintrading.com|//+------------------------------------------------------------------+#property copyright "BrainTrading Inc. System 7.0"#property link      "http://www.braintrading.com" #property indicator_chart_window#property indicator_buffers 2#property indicator_color1 Blue#property indicator_color2 Red //---- double Ind_Buffer1[];double Ind_Buffer2[];double spread;//---- bool   river = True;int    artp, limit, Curr, glava; double dartp, cecf, Emaxtra, widcha, TR;double Values, ATR, Weight, val1, val2, low, high, Series1; //---- Introduction of variables for multiple re-counting of the null bar bool   RIVER; int time2, GLAVA; double EMAXTRA,VALUES; //+------------------------------------------------------------------+//| BrainTrend2 initialization function                              |//+------------------------------------------------------------------+int init(){//----    SetIndexStyle(0, DRAW_HISTOGRAM);   SetIndexBuffer(0, Ind_Buffer1);   SetIndexStyle(1, DRAW_HISTOGRAM);   SetIndexBuffer(1, Ind_Buffer2);   spread = MarketInfo(Symbol(), MODE_SPREAD)*Point; //----   dartp = 7.0; cecf = 0.7; artp = 7;   //---- change of the buffer size to the required size   ArrayResize(Values, artp);//---- similar change of the memory buffer size in the first measuring//   to the required size   ArrayResize(VALUES, artp); //----   return(0);}//+------------------------------------------------------------------+//| BrainTrend2 iteration function                                 |//+------------------------------------------------------------------+int start()   {//---- check whether the amount of bars is enough to calculate   if(Bars < 11)       return(0); //----+ Introduction of integer variables and getting of bars already counted   int limit, MaxBar, bar, J, counted_bars = IndicatorCounted(); //---- check for possible errors   if(counted_bars < 0)      return(-1);//---- the last counted bar must be re-counted   if(counted_bars > 0)      counted_bars--;//---- determining of the oldest bar number, starting from which //   all bars will be re-counted   MaxBar = Bars - 3; //---- determining of the oldest bar number, starting from which //   only new bars will be re-counted   limit = (Bars - 1 - counted_bars); //---- initialization of null   if(limit >= MaxBar)   {       limit = MaxBar;       Emaxtra = Close;       glava = 0;       double T_Series2 = Close;       double T_Series1 = Close;       if(T_Series2 > T_Series1)            river = True;      else             river = False;       for(int ii = Bars - 1; ii > MaxBar; ii--)          {            Ind_Buffer1 = 0.0;         Ind_Buffer2 = 0.0;                  }   } //----//+--- restoring of values of variables +================+   int Tnew = Time;    if(limit < MaxBar)       if(Tnew == time2)         {            for(int xx = 0;xx <= artp - 1; xx++)                Values = VALUES;         glava = GLAVA;         Emaxtra = EMAXTRA;         river = RIVER;         }         else          {         if(Tnew > time2)               Print("ERROR01");         else               Print("ERROR02");         return(-1);         } //+--- +==================================================+//+--- Basic loop of the indicator calculation    bar = limit;   while(bar >= 0)         {         //+--- Saving values of variables +================+         if(bar == 1)         if(((limit == 1) && (time2 != Time)) || (limit > 1))            {               for(int kk = 0;kk <= artp - 1; kk++)                  VALUES = Values;               GLAVA = glava;               EMAXTRA = Emaxtra;               RIVER = river;               time2 = Time;             }      //+---+============================================+       Series1 = Close;       low = Low;      high = High;       TR = spread + high - low;       if(MathAbs(spread + high - Series1) > TR )             TR = MathAbs(spread + high - Series1);       if(MathAbs(low - Series1) > TR)             TR = MathAbs(low - Series1);       if(bar == MaxBar)            for(J = 0; bar <= artp - 1; J++)                Values = TR;         Values = TR;       ATR = 0;       Weight = artp;       Curr = glava;       for(J = 0; J <= artp - 1; J++)          {            ATR += Values*Weight;         Weight -= 1.0;         Curr--;         if(Curr == -1)                Curr = artp - 1;         }      ATR = 2.0*ATR / (dartp*(dartp + 1.0));       glava++;       if(glava == artp)            glava = 0;       widcha = cecf*ATR;       if(river && low < Emaxtra - widcha)          {            river = False;         Emaxtra = spread + high;         }      if(!river && spread + high > Emaxtra + widcha)          {            river = True;         Emaxtra = low;         }       if(river && low > Emaxtra)          {            Emaxtra = low;         }       if(!river && spread + high < Emaxtra )          {            Emaxtra = spread + high;         }       //Range1 = iATR(NULL,0,10,bar);       if(river==true )          {            val1 = high;         val2 = low;         }      else          {            val1 = low;         val2 = high;         }       Ind_Buffer1 = val1;      Ind_Buffer2 = val2;         bar--;   }   //+--- termination of the basic loop   return(0);}
好了,最后很招人爱的 ZigZag 指标,如我们在技术分析里看到的,也是在所有的柱体上重新计算的,因此,提出这个问题!我想没必要在这篇文章中将这个指标的代码贴出来,因为可以在 MetaTrader 4 客户端的 "indicators" 文件夹中将其打开。
当然,在这个指标中,综合上述思路编写的更多使用电脑资源的存储代码看起来非常易使人上当的,可怕的和麻烦的。此时,我们可以表现得不同。如果重新计算指标后,我们对最后版本的 ZigZag 指标虚线记录坐标和最后两个值,我们将在将来,下一次运行 int start() 函数完全正确的重算没有计算过的,与这两个坐标最近的指标值。而这两个最后的没有计算的的高点可以从内存中取值。必须说的是,这个指标不能完全正常的运作,并且周期性的会偏离正确的运作,但用来和前面的指标组合,它还是受人喜欢的。既然 ZigZag 指标至少有三个最高点总是会与图表偏离,我们将开始严密地指标计算,从这个类型到指标的虚线变形开始的最后处。在这个案例里,代码应该这样改变:

//+------------------------------------------------------------------+//|                                                       ZigZag.mq4 |//|                      Copyright 漏 2005, MetaQuotes Software Corp.|//|                                       http://www.metaquotes.net/ |//+------------------------------------------------------------------+#property copyright "Copyright 漏 2005, MetaQuotes Software Corp." #property link      "http://www.metaquotes.net/"#property indicator_chart_window#property indicator_buffers1#property indicator_color1 Red #property indicator_width1 0#property indicator_style1 1//---- extern int ExtDepth = 12; extern int ExtDeviation = 5;extern int ExtBackstep = 3; //---- double ZigZagBuffer[];//+------------------------------------------------------------------+//| ZigZag initialization function                                 |//+------------------------------------------------------------------+int init()   {    //----   SetIndexBuffer(0, ZigZagBuffer);   SetIndexStyle(0, DRAW_SECTION);    SetIndexEmptyValue(0, 0.0);    IndicatorShortName("ZigZag(" + ExtDepth + "," + ExtDeviation + "," +                     ExtBackstep + ")");    //----   return(0);   } //+------------------------------------------------------------------+//|ZigZag iteration function                                       |//+------------------------------------------------------------------+int start(){    //+ check whether the amount of bars is sufficient for correct    //calculation of the indicator   if(Bars - 1 < ExtDepth)      return(0);    //+ Introduction of integer memory variables to re-count the indicator   //on uncounted bars only   static int time2, time3, time4;      //+ Introduction of floating-point variables to re-count   //the indicator on uncounted bars only    staticdouble ZigZag2, ZigZag3, ZigZag4;    //+ Introduction of integer variables to re-count the indicator only    //on uncounted bars and getting of indicators already counted   int MaxBar, limit, supr2_bar, supr3_bar, supr4_bar;    int counted_bars = IndicatorCounted();    // check for possible errors   if(counted_bars < 0)      return(-1);    // the last counted bar must be re-counted   if(counted_bars > 0)         counted_bars--;    //----+ Introduction of variables      int shift, back, lasthighpos, lastlowpos;    double val, res, TempBuffer;    double curlow, curhigh, lasthigh, lastlow;    // determining of the oldest bar number, starting from which   // all bars will be fully re-counted   MaxBar = Bars - ExtDepth;   // determining of the start bar number in the loop, starting from   // which new bars will be re-counted    if(counted_bars == 0)         limit = MaxBar;    else       {      //----      supr2_bar = iBarShift(NULL, 0, time2, TRUE);      supr3_bar = iBarShift(NULL, 0, time3, TRUE);      supr4_bar = iBarShift(NULL, 0, time4, TRUE);      //----         limit = supr3_bar;            if((supr2_bar < 0) || (supr3_bar < 0) || (supr4_bar < 0))         {            limit = MaxBar;            Print("Start bar was not found,",             " the indicator will be re-counted on all bars" );          }      }    // initialization of null    if(limit >= MaxBar)       {         for(shift = Bars - 1; shift >= MaxBar; shift--)             ZigZagBuffer = 0.0;         limit = MaxBar;       }   // change of the temporary buffer size   if(ArrayResize(TempBuffer, Limit + ExtBackstep + 1)!=      limit + ExtBackstep + 1)      return(-1);   //+ start of the first large loop    for(shift = limit; shift >= 0; shift--)       {      //---         val = Low;      if(val == lastlow)            val = 0.0;      else         {             lastlow = val;             if((Low - val) > (ExtDeviation*Point))               val = 0.0;            else               {                for(back = 1; back <= ExtBackstep; back++)                   {                  res = ZigZagBuffer;                  if((res !=0 ) && (res > val))                        ZigZagBuffer = 0.0;                   }            }         }         ZigZagBuffer = val;      //---         val = High;      if(val == lasthigh)            val = 0.0;      else         {            lasthigh = val;            if((val - High) > (ExtDeviation*Point))               val = 0.0;            else               {                for(back = 1; back <= ExtBackstep; back++)                   {                  res = TempBuffer;                  if((res != 0) && (res < val))                      TempBuffer = 0.0;                   }               }         }      TempBuffer = val;      }    //+ end of the first large loop      // final cutting   lasthigh = -1;   lasthighpos = -1;    lastlow = -1;      lastlowpos = -1;    //----+ start of the second large loop    for(shift = limit; shift >= 0; shift--)       {      curlow = ZigZagBuffer;      curhigh = TempBuffer;      if((curlow == 0) && (curhigh == 0))             continue;      //---         if(curhigh != 0)          {            if(lasthigh > 0)               {               if(lasthigh < curhigh)                     TempBuffer = 0;                else                      TempBuffer = 0;            }            if(lasthigh < curhigh || lasthigh < 0)               {                lasthigh = curhigh;                lasthighpos = shift;            }             lastlow = -1;          }      //----      if(curlow != 0)         {            if(lastlow > 0)            {               if(lastlow > curlow)                     ZigZagBuffer = 0;                else                   ZigZagBuffer = 0;            }             //---            if((curlow < lastlow) || (lastlow < 0))               {                lastlow = curlow;                lastlowpos = shift;            }             lasthigh = -1;          }       }    //+ end of the second large loop    //+ start of the third loop    for(shift = limit; shift >= 0; shift--)       {      res = TempBuffer;      if(res != 0.0)             ZigZagBuffer = res;      }   //+ end of the third loop    //+ Restoring of values of the indicator buffer that   //could be lost   if(limit < MaxBar)      {         ZigZagBuffer = ZigZag2;         ZigZagBuffer = ZigZag3;         ZigZagBuffer = ZigZag4;         for(int qqq = supr4_bar - 1; qqq > supr3_bar; qqq--)             ZigZagBuffer = 0;         for(int ggg=supr3_bar - 1; ggg > supr2_bar; ggg--)             ZigZagBuffer = 0;      }    //+ correction of hills   double vel1, vel2, vel3, vel4;    int bar1, bar2, bar3, bar4;    int count;    if(limit == MaxBar)      supr4_bar = MaxBar;    for(int bar = supr4_bar; bar >= 0; bar--)       {      if(ZigZagBuffer != 0)          {             count++;            vel4 = vel3;            bar4 = bar3;            vel3 = vel2;            bar3 = bar2;            vel2 = vel1;            bar2 = bar1;            vel1 = ZigZagBuffer;            bar1 = bar;            if(count < 3)                continue;            if((vel3 < vel2) && (vel2 < vel1))                ZigZagBuffer = 0;            if((vel3 > vel2) && (vel2 > vel1))               ZigZagBuffer = 0;            if((vel2 == vel1) && (vel1 != 0))               ZigZagBuffer = 0;                }      }   //+ memorizing of the last three inflections of the ZigZag and   //the indicator values at these points      time2 = Time;    time3 = Time;    time4 = Time;    ZigZag2 = vel2;      ZigZag3 = vel3;   ZigZag4 = vel4;      //---- completion of calculating the indicator values    return(0);} //---+ +----------------------------------------------------------+
按照现在的情况,ZigZag 占用的宝贵的电脑资源少了,从以前的经验来看,不管其可用性多高,总是不足的。我为指标缓冲改了个更明显的名字 "ZigZagBuffer"。 我把第二个缓冲用来存储临时数据,替代了指标缓存因为这儿并不需要它,并且改名为 "TempBuffer"。在三个指标计算的循环里,我把变量 "limit" 作为开始的柱体数,只有没计算过的柱体值从这儿开始重新计算。
每个指标都是唯一的,几乎不可能创建一个在全部指标中都能同样运行的方法。但是我假设这样的方法的通常思路是相当清楚的:
1. 在先前的价位上确定所有的变量是最难的。我们必须考虑到,有时需要记录一些变量和柱体数,这个柱体可以在下一个价位改变,而保存的值却没有任何改变。在这个案例中,柱体开始的时间必须被记录(MEMORY_bar_time = Time)。然后当前的柱体状态可以通过被记录的时间重建(iBarShift(NULL,0,MEMORY_bar_time,TRUE))。指标计算了几个循环后,每个循环都有变量要储存,同样的变量在不同的循环里必须被分开来储存。
2. 初始化的变量要与申明的变量名字一致。最好在指标代码的开始处申明全局变量。在 start() 运作后,在指标代码里,这些变量经常被立即申明作为静态变量。
3. 在所有指标计算的循环前,必须写变量重建的代码。
4. 在每一个包含当前变量的循环里,应该添加存储这些变量的代码。

最后,我想说的是所有在本文中作为例子的指标,都可以在网络的不同论坛里获得源代码。 我把它们只作为例子分享,纠正其中的错误,如果有任何侵权的责任应归于把他们放到网站上的人。
Nikolay Kositsin

MetaQuotes Software Corp. 翻译自俄语
原文: http://articles.mql4.com/ru/139


附件:
http://www.mql4.com/i/ico/zip.gif NullBarReCount.zip (12.9 Kb)
创建: 2006.12.06创建人: Nikolay Kositsin

hefeiddd 发表于 2008-5-25 07:28

巨大程序中定单的考虑 [ en | ru ]http://www.mql4.com/i/print.gif

如果一个交易策略打算运行一定数量的定单 (例如,一个买入定单和一个卖出定单),这样智能交易在实行这些策略时可能不会考虑这些定单的差别。智能交易只是在自己构想的基础上决定交易,即,在终端内不能存在不同方向的定单。
这种方法基本上被接受,但是它仅适用于一小部分程序并不能做到普及。如果相同货币对存在两个或多个不同形式的定单,那么,智能交易应该怎样做呢? 可以说是违背,交易策略没有预见过这种情况并且不会发生。我们需要解决这个缺陷并且限定这个构想。
作为拥有丰富经验的交易者使用几个定单交易 (包括挂单交易),交易者将需要考虑所有定单的可用性。因为挂单交易可以转至开仓。此外,众所周知,交易者可以忘记在终端内正在运行的智能交易,随时可以手动开仓。几个交易者在一个账户上执行交易同样存在。这种情况下,交易策略本身会运行较大数量的定单。
我们尝试考虑在巨大程序中很好地考虑定单。
1. 环境的特性和概要我们来简短描述一下程序运行的环境特点。
1.首先,我们确定要知道程序中定单的数量和类型(考虑数据会由程序收集)。 不能简简单单地说,我们的程序中有3个卖单和4个买单。任何智慧的交易系统都包含一个检测定单的计算 -止损水平和赢利水平,挂单交易开盘价。另外 我们需要知道每个定单的价值,它的期限,什么样的程序可以放置。
2.替克数。如果及时查看任何信息,都会带来一定意义。任何智能交易都会终端内处理开价。很明显,定单的状态会因为价格的改变而改变。这就意味着每个替克必须"重新考虑"。
3. 智能交易在窗口中获取的货币对可以把它列为 "一般特性".
在这些简单的数据基础上,我们能够测定出创建考虑定单智能交易的基本原理。
首先, 考虑定单的智能交易,其交易系统必须能够解决相应的问题。例如,分析可用性、定单的质量、关注这些数据、 决定交易。 如果状况是已知的情况,那么当前状况的任何分析都可能出现。这就说明程序代码已经开始考虑定单,并且在其他代码之前执行定单的代码。我们最好把形成考虑代码作为一个单独的函数。我们把它称作 Terminal(),因为它的主要任务是在终端内关注定单。
第二,由Terminal()函数所累积的数据必须使用于其他函数。这就是为什么显示有用信息变量的定单必须被纳入到整体水平 (不与GlobalVariables混淆)的原因。
第三,既然我们处理信息设定,必须在定单数组的基础上合乎逻辑地组织考虑。

2. 程序的结构根据上述的讲解,我们创建一个常规可以考虑定单的程序结构:


// My_expert.mq4//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж#include ...#include <Peremen.mq4>    // Description of the expert's variables.   #include <Terminal.mq4>   // Attach the Terminal function.#include <Sobytiya.mq4>   // Attach the Sobytiya function.#include ...//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж//// //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint init()   {   ...                  // 函数代码init()   return;   } //=================================================================int start()    {   Terminal();            // 该函数在函数的顺序上                           // 要排在第一位   ...                  // 其次是start()函数代码   Sobytiya();            // 事件处理函数   ...                  // 其次start()函数代码   return;                                                                  }//=================================================================int deinit()    {      ...                  // deinit()函数代码   return;   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
Peremen.mq4 文件描述变量必须包含数组的描述给出定单的数据。


//Peremen.mq4//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж//==================================================================int...//==================================================================double...Mas_Ord_Tek, Mas_Ord_Old, // 定单的当前数组和旧数组// 第一个指数 = 在该数组中的定单数字// [] 未指定// [] 开单汇率(汇率的绝对值)// [] 止损定单(汇率的绝对值)// [] 赢利定单(汇率的绝对值)// [] 定单数字      // [] 定单中的标准手数(汇率的绝对值)// [] 定单类型1=B,2=S,3=BL,4=SL,5=BS,6=SS// [] 定单的Magic Number ...//=================================================================string ...//=================================================================//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
当在较小程序中指定整体变量时,通常在第一个函数进入之前编写。在中等和较大的程序中,会在一个文件内收集全部整体变量并且把这个文件附加到智能交易使用的#include上。

在代码的效率上,在方法和不重要之间出现不同。但是在可用性上,附加的文件上时可取的。这也是一种附加
Peremen.mq4
文件到以上智能交易示例的一种方法。

3. 数组在 Peremen.mq4文件中,两个数组被指定作为整体变量:
Mas_Ord_Tek - 定单当前数组。
Mas_Ord_Old -定单的旧数组。
为什么我们需要使用不是一个数组,而两个呢? 为的是能够检测事件。至于是什么事件,我们将会晚些讨论。现在,让我们来谈谈以比较初始状态和当前状态比较为基础的指定事件本身。如果不存在任何状态数据,就不可能指定事件。这种情况下,定单的数组被用作通知交易空间状态前后的替克。
为什么使用2D 数组? 因为我们考虑到几个定单同时运行并且保持其中每个定单的几个特性。在数组中第一个指数为定单数字,第二个指数为定单标准特性。在上面的示例中,在终端内第一个指数不允许超过30个定单变量。您可以根据自己的需要改变这个总数。例如,在终端内同时运行 50或100定单。当然,如果你的智能交易系统允许运行这些定单的总数,可以执行改变。在标准状况下,使用 1到 2个定单,较大的范围,我认为4. 30已经很多了。
为什么在括号中给出的数组是 31 和 8,而不是 30 和 7呢?这是因为在 MQL4中数组计数是从零开始 。使用零开始计数在整体元素中有它的道理。我认为,使用定单数字(号码)作为相应的数组元素号码是符合逻辑的。例如,第三个定单必须在指数3的线内。事实上,这个线将是第四个,但是它的指数为3 。因为第一个线指数为0 。
现在我们来看看以下表格中插入的数组。建议仅存3个定单: Buy, Sell和不同质量的 BuyStop:


http://articles.mql4.com/c/articles/2008/04/Massiv_4_.gif


定单的信息被放置在数组中的号码是从到 to 。另外,我们将在数组定单总数量中放置的元素指数为。这种情况下为 3。在以后的计算中,这个号码将被使用于当前分析状态的循环组织 。
因此, 我们能够存储接近30个定单的信息,每个定单的特性为 7个。
如果你的交易策略建议同时交易几种货币对,你可以开设一个数组号码并且按照当前货币对放置定单。这种方法能够达到目的,但是并不方便。如果用这种方法考虑定单的组织,你需要开设其他数组用来存储包含定单信息的数组名称。
一个较为方便的解决方法可以使用较大的数组考虑全部定单。这种选择更好些,在将来代码的处理中,将不再需要搜索货币对定单数组的名称。在一个接一个的模式数字循环中将正好被使用。
包含全部被组织定单的数组如下:


http://articles.mql4.com/c/articles/2008/04/Massiv_2_2_.gif


每种货币对的定单信息存储在相同的指数水平内,如上示例。不同组成的在于,在这种情况下,一些水平的号码(在途中,其中的3个:黄色,粉色和绿色)。他们的总数等于我们当前运行的总数(加上一个)。在这个水平中 (灰色),只有一个值,定单的总数被存储在指数做为 中。
数组范围, 25第一个指数货币对将为26。这种情况下,
Peremen.mq4
文件描述数组将如下:


//Peremen.mq4//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж//===========================================================================int...//===========================================================================double...Mas_Ord_Tek, Mas_Ord_Old, //定单的当前数组和新数组// 第一个指数 = 货币对号码// 第二个指数= 定单号码 ...// ... 货币对水平// [][] 未指定// [][] 开单汇率   (汇率的绝对值)// [][] 止损定单   (汇率的绝对值)// [][] 赢利定单   (汇率的绝对值)// [][] 定单号码       // [][] 定单的标准手数   (汇率的绝对值)// [][] 定单类型 1=B,2=S,3=BL,4=SL,5=BS,6=SS// [][] 定单的MagicNumber//=================================================================string       Instrument;                   // 货币对名称数组...//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж//////жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint Predopred()   {//================================================= 预定义 =   Instrument = "EURUSD";   Instrument = "GBPUSD";   ...   Instrument= "AUDCAD";//==================================================================   return();   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
在这个文件底部中打开变量,数组instrument被打开。
一个较大的程序通常存在许多变量,在程序执行期间这些值不能改变。在我们的情况中,Instrument[] 数组为这些元素。对于程序更加方便,能够在一个很函数中更好地收集一些变量。这个变量同样可以是作为单独文件模式被附加到程序使用的 #include。
在下面的示例中,我们在包含相同 Peremen.mq4 文件Predopred() 函数中看看Instrument[]数组元素的预定义。 这个函数只够开启一次,所以在程序中包含特殊函数名称为 init():


int init()   {   Predopred();         // 一些变量的预定义   return;   }
在我们的情况中包含一些整数,因此,Instrument[]数组指数的值作为相应货币对的号码。.

4. 考虑定单的函数现在让我们来看看对于一种货币对考虑定单的函数 Terminal() 。这个函数同样是一个单独文件被命名为 Terminal.mq4,并且附加到智能交易上使用 #include 。


// Terminal.mq4//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint Terminal()   {//================================================ 预定义 ==   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek);// 保存先前历史   int Kol=0;                     // 定单计数归零
//=============================================== 定单分析 ==   for (int i=0; i<OrdersTotal(); i++) // 终端内的全部定单   {      if((OrderSelect(i, SELECT_BY_POS)==true) &&                     (OrderSymbol()==Symbol()))                        //如果存在下一个和我们的货币对 {                                                                           Kol++;                   // 计算定单的总数//--------------------------- 模式化定单的新数组 --      Mas_Ord_Tek = NormalizeDouble(OrderOpenPrice(),                                              Digits); // 开单汇率               Mas_Ord_Tek = NormalizeDouble(OrderStopLoss(),                                              Digits); // 止损汇率               Mas_Ord_Tek = NormalizeDouble(OrderTakeProfit(),                                              Digits); //赢利汇率                Mas_Ord_Tek = OrderTicket();      // 定单号码      Mas_Ord_Tek = OrderLots();      // 标准手数计算      Mas_Ord_Tek = OrderType();      // 定单类型      Mas_Ord_Tek = OrderMagicNumber(); // Magic number //-----------------------------------------------------------------       }   }   Mas_Ord_Tek = Kol;   // 保存零//=================================================================   return();   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
首先要做的是在系统通过Terminal()函数的检测后被保存到定单的先前状态。在 Mas_Ord_Tek[][] 数组中,但是在当前时刻不是真实的,因为反映的是在先前替克上模式化定单的状态。在初始时刻当前状态未知。

在字行中


   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek); // 保存先前历史
定单的最近已知状态被 Mas_Ord_Old[][]数组通过。
使用到地方变量的函数命名为 Kol 并且反映当前定单的总数。 必须要使用这个变量生成,因为 MQL4 不允许使用指定指数。在代码中可以看出,它作为指数值使用。 我们归零这个变量,以及作为整个当前变量的数组并且注意实际状况。
这样做,我们组织一个终端的循环,即连续调用全部可用定单并且找出它们的特性。


   for (int i=0; i<OrdersTotal(); i++) // 终端中的全部定单
请注意:
OrdersTotal()
确定定单总数,并且在终端内开始为0时数定单的号码。这就是为什么 "
< " 被使用到循环线并且以零循环开始的整体变量改变的原因:
i
=
0
.


在以下的代码中,附加到智能交易上的货币对定单被着重强调。使用函数确定不同定单的特性,获取的信息放置到相应的 the Mas_Ord_Tek[][] 数组中。


//---------------------------模式化定单的新数组 --       Mas_Ord_Tek = NormalizeDouble(OrderOpenPrice(),                                             Digits); // 开单汇率            Mas_Ord_Tek = NormalizeDouble(OrderStopLoss() ,                                             Digits); // SL 汇率            Mas_Ord_Tek = NormalizeDouble(OrderTakeProfit(),                                             Digits); // ТР 汇率             Mas_Ord_Tek = OrderTicket();      // 定单号码       Mas_Ord_Tek = OrderLots();      // 标准手数                                                // 计算       Mas_Ord_Tek = OrderType();      // 定单类型       Mas_Ord_Tek = OrderMagicNumber(); // Magic number //------------------------------------------------------------------
在通过中计数被提填充 ,将通过它的值数组零元素循环到底部归零。


   Mas_Ord_Tek = Kol;      // 保存零
对于同时运行的几种货币对,Tеrminal() 函数的构造如下:


// Terminal.mq4//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint Terminal()   {//================================================== 预定义 =   ArrayCopy(Mas_Ord_Old, Mas_Ord_Tek); // 保存先前历史   ArrayInitialize(Mas_Ord_Tek,0);// 当前定单数组归零//==================================================定单分析=   for (int i=0; i<OrdersTotal(); i++)//终端的全部定单      {      if(OrderSelect(i, SELECT_BY_POS)==true) // 如果存在“即时”交易         {//--------------------------------------- 指定货币对指数-         string Symb=OrderSymbol();// 查明当前定单货币对         for (int ind=1; ind<=25; ind++)// 在货币对数组中搜索            {            if (Symb==Instrument)// 找到指数,搜索完成               break;            // 退出循环            }//------------------------模式化定单的新数组 ----         Mas_Ord_Tek++; // 计算定单总数         Mas_Ord_Tek++; // 计算一种货币对的定单总数         int k=Mas_Ord_Tek;   // 模式化变量                  Mas_Ord_Tek = NormalizeDouble(OrderOpenPrice(),                                                Digits); // 开单汇率                  Mas_Ord_Tek = NormalizeDouble(OrderStopLoss(),                                                Digits); // SL 汇率               Mas_Ord_Tek = NormalizeDouble(OrderTakeProfit(),                                                Digits); // ТР 汇率                  Mas_Ord_Tek = OrderTicket(); // 定单号码         Mas_Ord_Tek = OrderLots();   // 标准手数计算         Mas_Ord_Tek = OrderType();   //定单类型         Mas_Ord_Tek = OrderMagicNumber(); // Magic                                                      // number          //-----------------------------------------------------------------         }      }//=================================================================   return();   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
对于多种货币对的考虑定单计算不同于一种货币对,它通过一个很小的区域查明货币对的指数。


//----------------------------------- 指定货币对指数----         string Symb=OrderSymbol(); // 查明当前定单的货币对         for (int ind=1; ind<=25; ind++) //在货币对数组中搜索            {            if (Symb==Instrument) // 指数找到,完成搜索               break;            // 退出循环            }
在Terminal()函数的连续线中,
找到货币对指数值
ind 查明数组的水平指数,其包含数据定单相关货币对的定单。


在上面Terminal()函数的真实示例中,一些变量的计算使用了正常化:


Mas_Ord_Tek = NormalizeDouble(OrderOpenPrice(),                                       Digits); // 开单汇率Mas_Ord_Tek = NormalizeDouble(OrderStopLoss(),                                       Digits); // SL 汇率Mas_Ord_Tek = NormalizeDouble(OrderTakeProfit(),                                       Digits); // ТР 汇率
使用这些计算查明是为了将来在交易业务中使用正常化变量值。另外,有效数字的总数需要在预定义变量数字基础上查明。

一个交易系统可以考虑其他特性和定单的特性。但是在上面的示例中所给出的只是在较大程序中考虑定单的基本原理。例如,在这里我们不讨论平单和删除定单,也不考虑一些其他定单的特性。例如,挂单交易的时间期限。如果您需要处理以上特性,您可以轻松地确认数组在定单的附加数据中存储。比如,您可以增加最近指数元素总数,将其储存为挂单交易的时间期限值。


5.事件的处理在这里由Tеrminal()函数引发了一个新的替克 。检测被交易业务通过,在函数 Terminal()之后立即被地方化。 不能提前预测特殊函数start()在那个部分或其他事件的处理自定义函数必须被放置 - 它取决于交易系统的想法。在一些简单的情况中,一些事件可以立刻解决。

在给出如何处理事件的范例之前,我想要提醒交易者在有些特殊的情况下这种解决方法并不能处理事件。

第一,一些证券交易人 (银行,例如,他们的特殊账户)。他们的账户在一天结束后会关闭所有定单,第二天早晨会开单。银行会根据汇率点数区分当前定单。 这些点数的掉期汇进入到定单经济中。掉期本身会作为零显示在终端内。这种情况下,类似银行的证券交易人不能遵循这个规则。对于我们而言,在这种情况下重要的是新开单并获取定单号码,其定单与先前的完全不同。
第二,平单分为两个单独的完成。第一步,完全关闭定单。第二步,打开价格略低的新定单并使用新单号码。另外, 最初定单号码被写入到新定单的注解中。
第三,当使用其他定单平单时,如果两个定单的价格不同,会出现 类似的错误。这种情况下,定单会重复部分平单。
识别定单的唯一机会是初始化定单的一些特性,使其不发生改变并且不重复。MQL4会提供机会,我能够找到这样一个参量 - MagicNumber。但是,在这种情况下,创建者也不能计算完整检测的创建。主要的原因是创建者不能改变 MagicNumber。一方面的优势:我们可以确信只要定单存在,这个参量便不会改变。另一方面,则不能够根据程序需要调整可取的参量。当前情况下便没有机会改变。所以,如果定单(一个或多个)不是在我们自己的交易系统中打开, 而是其他程序或手动打开,这样便没有方法识别定单是 "自己的" 还是其他。


一个较弱的特殊识别符开单时进行服务。但是这个标准不能考虑稳定性和普遍性。因为在理论上有可能几个定单同时打开 (同一秒钟)。例如,如果价格迅速地变化,不同货币对的两个挂单交易会同时打开。


让我们从包含Sobytiya.mq4文件的
Sobytiya()
函数中学习真实范例。我们将观看一个简单的事件 - 一个定单的删除或关闭。 We have already
我们知道定单号码有时会不合适,所以我们来分析
MagicNumber。
.


// Sobytiya.mq4   //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint Sobytiya()   {//==================================== 搜索亏损定单 ====   for (int oo=1;oo<=Mas_Ord_Old;oo++)   // 从旧数组中拿走定单号码      {         int Sovpadenie=0; // 使符合状态归零      for (int i=1;i<=Mas_Ord_Tek;i++)   // 在当前的数组中尝试找出这个定单          {         if (Mas_Ord_Tek==Mas_Ord_Old) // 如果定单MagicNumber 适合, 记住 // 退出循环模式
            {            Sovpadenie=1;            break;             }         }            if (Sovpadenie==1) continue;                  // 去下一个旧数组      Alert("平单 ",Mas_Ord_Old);   // 在屏幕上显示信息文本      PlaySound( "Close_order.wav" );// 音乐      }//=================================================================   return();   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
正如你所看到的,如果你能够准确地描述注视的事件,你可以轻松地处理它。 可以充分地连续比较定单之前和之后的替克 - 明显看到他们之间存在差别。这样我们可以确定事件发生了。
在下一个示例中,我们考虑了其他事件的搜索 - 定单类型修改。这里我们使用的是相同原理,但是需要提供其他的标准。使用的定单号码和类型分析。


// Sobytiya_2.mq4   //жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжint Sobytiya_2()   {//============ 搜索定单改变其类型 ====   for(int oo=1;oo<=Mas_Ord_Old; oo++)               // 穿过旧数组      {      for (int i=1;i<=Mas_Ord_Tek;i++)               // 在当前的数组中搜索定单         {         if (Mas_Ord_Tek == Mas_Ord_Old &&    // 如果旧数组中包含相同定单,但是不同类型, // 那么: 实行挂单交易             Mas_Ord_Tek != Mas_Ord_Old)                  {               Alert("定单转换",Mas_Ord_Tek);// 在屏幕上显示信息文本            PlaySound("Transform.wav" );   // 音乐            }         }      }//=================================================================   return();   }//жжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжжж
在智能交易中程序的创建是依赖创建者的构想完成的,所以事件可能在程序的不同位置。如果需要,可以将模式化的所有事件放置在一个文件中。另外,在定单中的这些代码需要修改几次,为得是在数组搜索的运行中无须根据每个标准经常停顿。 对于将来的分析同样很容易的出现一种计算方法,从关闭定单的部分注解中提取初步号码进行计算。做到这些需要使用OrderComment() 函数。
除了上述的一些特性外,智能交易定单的考虑还存在一些其他方法。让我们仔细地看看,使其帮助我们拓宽真实智能交易的认知并且避免一些不必要的错误出现。那么我们回到交易者交易日结束的平单。

通常掉期值是不能够以点数进行划分的,我们将定单汇率值的有效总数结果增加 1。这个特性地考虑需要把这个值正常化,然后将其值将精确到数字1 以上:


Mas_Ord_Tek = NormalizeDouble(OrderOpenPrice(),                                       Digits+1); // 开单汇率
另外,在这种状况下需要注意开单的汇率可能会改变定单的状态。如果交易者使用一个交易系统决定关注开单汇率,那么这个交易系统只能坚持一天之久。纵观整个交易,我们可以得出结论开单的汇率根本没有连续性!一个重要的因素是状态的发展趋势。如果与我们的状态相反,选择平仓。
在这篇文章里我们谈及到了影响交易决定的标准。但是对于任何交易策略,在程序中我们仍然有必要选择使用标准 。
转自俄罗斯 MetaQuotes Software Corp.
原文: http://articles.mql4.com/ru/114
创建: 2008.04.01创建人: Sergey Kovalyov

hefeiddd 发表于 2008-5-25 07:29

MagicNumber: 定单的“魔法“识别符 [ en | ru ]http://www.mql4.com/i/print.gif
1. 历史在МТ3中,开仓的管理是非常费时的。交易者在处理开仓和平仓列表时,设置执行的工具是限定的。在区分“自己”和“他人”仓位时,方法非常复杂。在 МТ4中,状况有了明显的改变。现在,交易者可以使用多种函数来管理开仓,挂单并且获取平仓信息。
以MagicNumber命名的特殊参数被添加到定单识别符中。这个参数就是我们文章中将提及到的主题。


2.什么是 MagicNumber?MQL4 参考:


int OrderSend( string symbol, int cmd, double volume, double price, int slippage, double stoploss, double takeprofit, string comment=NULL, int magic=0, datetime expiration=0, color arrow_color=CLR_NONE)

magic - 定单魔法数字。可以使用指定识别符。


即,当定单被放置时,可以给定单指定独有的数字。这个数字将用于区分其他定单。当手动交易时,不使用(尽可能)这个特性,但是在智能交易(自动交易)运作时,此特性是不可替代的。

范例1: 在客户端内交易者和智能交易同时运行。
任务: 智能交易的运行必须按照它自己的形式计算,对于手动开仓不会干涉。
解决: 开仓的智能交易必须指定独特的MagicNumber(零除外)。接下来的日子里,智能交易只会管理提前设定的 MagicNumber 的定单。
范例 2: 在客户端内两个不同计算方法的智能交易同时运行。
任务: 智能交易只管理自己的定单。.
解决: 当开仓时,每个智能交易必须使用自己的 MagicNumber(零除外)。接下来的日子里,智能交易只会管理提前设定的MagicNumber的定单。
范例 3: 在客户端内几个智能交易,交易者和协助智能交易执行的不标准追踪止损同时运行。
任务: 交易的智能交易必须按照自己的形式计算,并且不干涉手动开仓。协助智能交易执行的追踪止损可以在手动开仓处修改,但是其他智能交易不能够开仓。
解决: 智能交易必须使用独有的MagicNumbers并且管理自己的仓位。协助智能交易修改的这些仓位,其 MagicNumber等于 0。
以上三个范例都很现实,用户可以提前解决问题。在这三个范例情况中,都是使用MagicNumber来解决问题的。这不是唯一解决问题的途径,但是最简单的途径。

3. 实践现在让我们来解决特殊的任务:创建智能交易只管理自己的仓位,不理睬手动仓位和其他智能交易。
首先我们编写一个简单的智能交易,当 MACD 指标零线时,智能交易得到信号开仓。智能交易将会运行如下:


int start(){    //---- 记住将要分析的指标值    //---- 注意:我们使用第一个和第二个柱。可以是每日的 1-bar 。   //---- (即., 信号晚些显现), 但是保护反复开仓和平仓    //---- 在柱内仓位的    double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 );    double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 );   int _GetLastError = 0, _OrdersTotal = OrdersTotal();    //---- 在开仓中搜索    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      //---- 如果在选择仓位中生成错误,转到下一步      if ( !OrderSelect( z, SELECT_BY_POS ) )      {            _GetLastError = GetLastError();            Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - Error #", _GetLastError );            continue;      }         //---- 如果开仓不是当前货币对,略过      if ( OrderSymbol() != Symbol() ) continue;         //---- 如果开仓为BUY,      if ( OrderType() == OP_BUY )      {            //---- 如果 MACD指标看到的零线从上至下,            if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )            {                //---- 平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) )                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose # ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变,退出: 开仓尚早            else return(0);      }      //---- 如果开仓位SELL,      if ( OrderType() == OP_SELL )      {            //----如果MACD指标看到零线从下到上,            if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )            {                //---- 平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) )                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose # ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变,退出:开仓尚早            else return(0);      }    } //+------------------------------------------------------------------+//| 如果达到此点,没有仓位开仓                            |//| 检测是否仍有开仓的可能                                  |//+------------------------------------------------------------------+   //---- 如果MACD 指标看到零线从下到上,    if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )    {      //---- 开BUY仓      if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test", 0, 0, Green ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    //----如果MACD 指标看到零线从上至下,    if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )    {      //---- 开 SELL 仓      if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test", 0, 0, Red ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    return(0);}
这样我们得到以下图表,看看它怎样运行:


http://articles.mql4.com/c/articles/2006/05/macd_test1.gif



http://articles.mql4.com/c/articles/2006/05/macd_test1.gif


都不错,但是这里有个问题存在。如果在智能交易执行期间开仓,智能交易将会默认为这个仓位为自己的仓位。这是我们不想看到的。
我们将按照以下方法让它管理自己的仓位:
[*]以Expert_ID 命名添加外部变量协助智能交易开仓来改变 MagicNumber 值[*]在函数OrderSelect()选择仓位之后,对编译Expert_ID变量所选定单的MagicNumber 添加检测[*]在开仓期间,我们将在MagicNumber处写下 Expert_ID的值替换 0考虑上面的变化,代码将显现如下:


extern int Expert_ID = 1234; int start(){    //---- 记住将要分析的指标值    //---- 注意:我们使用第一个和第二个柱。可以是每日的 1-bar 。   //---- (即., 信号晚些显现), 但是保护反复开仓和平仓    //---- 在柱内仓位的    double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 );    double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 );   int _GetLastError = 0, _OrdersTotal = OrdersTotal();    //---- 在全部开仓中搜索    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      //---- 如果在搜索仓位中生成错误。转到下一步      if ( !OrderSelect( z, SELECT_BY_POS ) )      {            _GetLastError = GetLastError();            Print( "OrderSelect( ", z, ", SELECT_BY_POS ) -错误 #", _GetLastError );            continue;      }         //---- 如果平仓仓位不是当前货币对,略过      if ( OrderSymbol() != Symbol() ) continue;         //---- 如果MagicNumber 不等于Expert_ID, 忽略此仓位      if ( OrderMagicNumber() != Expert_ID ) continue;         //---- 如果开BUY仓,      if ( OrderType() == OP_BUY )      {            //---- 如果MACD 指标看到零线从上到下,            if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )            {                //---- 平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) )                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose # ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变, 退出: 开仓尚早            else            { return(0); }      }      //---- 如果开SELL仓,      if ( OrderType() == OP_SELL )      {            //---- 如果MACD指标看到零线从下到上,            if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )            {                //---- 平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) )                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose № ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变,退出: 开仓尚早            else return(0);      }    } //+------------------------------------------------------------------+//| 如果执行达到此点,没有仓位开仓                          |//| 检测是否有可能开仓                                   |//+------------------------------------------------------------------+   //---- 如果MACD 指标看到零线从下到上,    if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )    {      //---- 开BUY仓      if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test",               Expert_ID, 0, Green ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    //---- 如果MACD 指标看到零线从上至下,    if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )    {      //---- 开SELL仓      if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test",               Expert_ID, 0, Red ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    return(0);}
现在,当智能交易运行时,用户可以手动开仓。智能交易将不会干涉。

4. 多个相同的智能交易在一种货币对的不同图表上存在这样的状况,相同的智能交易必须在相同货币对的图表中运行,但是需要不同的时间周期。例如,如果我们尝试添加我们的智能交易同时添加到 EURUSD, H1图表和 EURUSD, M30图表,他们将会相互影响:每个都会“考虑”开仓并且会默认管理。
这个问题可以通过 Expert_ID 一个协调另一个的方式解决。但是这羊不是很方便。如果很多智能交易在运行,他们的ID必然会混乱。
解决这个问题我们需要以 MagicNumber 值作为图表周期。怎样执行呢?如果我们添加图表周期到 Expert_ID, 可能2个不同的智能交易在2个不同的图表上生成相同的 MagicNumber。
所以我们最好用 Expert_ID值乘以 10 并且把图表周期(代码从1 到 9, 精确值)放置到最后。
如下图表:


    int Period_ID = 0;    switch ( Period() )    {      case PERIOD_MN1: Period_ID = 9; break;      case PERIOD_W1:Period_ID = 8; break;      case PERIOD_D1:Period_ID = 7; break;      case PERIOD_H4:Period_ID = 6; break;      case PERIOD_H1:Period_ID = 5; break;      case PERIOD_M30: Period_ID = 4; break;      case PERIOD_M15: Period_ID = 3; break;      case PERIOD_M5:Period_ID = 2; break;      case PERIOD_M1:Period_ID = 1; break;    }    _MagicNumber = Expert_ID * 10 + Period_ID;
现在添加这个代码智能交易的 init()函数并且用 Expert_ID替换MagicNumber。


最终版本的智能交易如下:


extern int Expert_ID = 1234;int _MagicNumber = 0; int init(){    int Period_ID = 0;    switch ( Period() )    {      case PERIOD_MN1: Period_ID = 9; break;      case PERIOD_W1:Period_ID = 8; break;      case PERIOD_D1:Period_ID = 7; break;      case PERIOD_H4:Period_ID = 6; break;      case PERIOD_H1:Period_ID = 5; break;      case PERIOD_M30: Period_ID = 4; break;      case PERIOD_M15: Period_ID = 3; break;      case PERIOD_M5:Period_ID = 2; break;      case PERIOD_M1:Period_ID = 1; break;    }    _MagicNumber = Expert_ID * 10 + Period_ID;
    return(0);} int start(){    //---- 记住将要分析的指标值    //---- 注意:我们使用第一个和第二个柱。可以是每日的 1-bar 。   //---- (即., 信号晚些显现), 但是保护反复开仓和平仓    //---- 在柱内仓位的    double MACD_1 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 1 );    double MACD_2 = iMACD( Symbol(), 0, 12, 26, 9, PRICE_CLOSE, MODE_MAIN, 2 );   int _GetLastError = 0, _OrdersTotal = OrdersTotal();    //---- 在全部开仓中搜索    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      //---- 如果在搜索过程中生成错误。转到下一步      if ( !OrderSelect( z, SELECT_BY_POS ) )      {            _GetLastError = GetLastError();            Print( "OrderSelect( ", z, ", SELECT_BY_POS ) - 错误#", _GetLastError );            continue;      }         //---- 如果开仓仓位不是当前货币对,忽略      if ( OrderSymbol() != Symbol() ) continue;         //---- 如果MagicNumber 不等于 _MagicNumber, 忽略此仓位      if ( OrderMagicNumber() != _MagicNumber ) continue;         //----如果开BUY仓,      if ( OrderType() == OP_BUY )      {            //---- 如果MACD指标看见零线从上至下,            if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )            {                //---- 平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Bid, 5, Green ) )                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose # ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变,停止: 开新仓位尚早            else return(0);      }      //---- 如果开SELL仓,      if ( OrderType() == OP_SELL )      {            //---- 如果MACD指标看见零线从下到上,            if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&                   NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )            {                //----平仓                if ( !OrderClose( OrderTicket(), OrderLots(), Ask, 5, Red ) )                {                  _GetLastError = GetLastError();                  Alert( "错误OrderClose № ", _GetLastError );                  return(-1);                }            }            //---- 如果警报没有改变, 停止: 开新仓位尚早            else return(0);      }    } //+------------------------------------------------------------------+//| 如果执行达到此点,没有仓位开仓                          |//| 检测是否仍有可能开仓                                |//+------------------------------------------------------------------+   //---- 如果MACD 指标看见零线从下到上,    if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )    {      //---- 开 BUY 仓      if ( OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "MACD_test",               _MagicNumber, 0, Green ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    //---- 如果MACD 指标看到零线从上至下,    if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )    {      //---- 开 SELL 仓      if ( OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0, "MACD_test",               _MagicNumber, 0, Red ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend # ", _GetLastError );            return(-1);      }      return(0);    }    return(0);}
这样的显示智能交易可以在不同周期的几个图表中使用。


如果需要在相同时间周期和货币对的图表(例如, EURUSD H1 和EURUSD H4)上开启两个智能交易, 此Expert_ID 变量值将被改变。但是这种情况很罕见。

使用以上代码,用户能够改善他的智能交易并且“教会”智能交易区分自己的仓位和他人的仓位。


转自俄罗斯MetaQuotes Software Corp.
原文: http://articles.mql4.com/ru/105

创建: 2008.03.10创建人: Andrey Khatimlianskyi

hefeiddd 发表于 2008-5-25 07:30

交易之间的停顿 [ en | ru ]http://www.mql4.com/i/print.gif

1.是必须还是好意?在 МetaТrader 3客户终端中,在两笔交易中需要停留10秒钟的时间。在 MetaQuotes Software Corporation 公司创建 МТ4时,出于交易者的意愿删除了这个限定。事实上,这种情况是接收一个接一个的交易执 (对于一些仓位移动止损水平,移除挂单交易等等)。但有些交易者认为交易之间的停顿是错误的,并且进行设置智能交易可以不间断的开仓。这种结果导致账户被封,在经纪的角度这是不友好的态度。
这篇文章的目的是使交易者和经纪人双方都能够感受到舒适的交易。

2. 一个智能交易或几个智能交易:它们又怎样的区别?如果您只有一个终端开启并且只有一个智能交易运行,它自己会很自然地安排交易之间的停顿::创建整体变量 (整体变量水平,不要与终端的整体变量混淆)并且存储到最近交易时间。当然,在你执行每笔交易之前, 你可以检测间隔时间是否能够接受。
请看示例如下:


datetime LastTradeTime = 0;int start() {// 检测是否进入市场...// 计算止损水平,赢利水平和标准手数   ...// 在最后一笔交易完成后检测停顿时间if(LocalTime() - LastTradeTime < 10)   {    Comment("在最后一笔交易完成后停顿少于10秒!",
      " 智能交易不能交易!");   return(-1);   }   // 开仓if(OrderSend(...) < 0)   {    Alert( "错误开仓位置 #
", GetLastError() );    return(-2);   }      // 记住最后交易时间LastTradeTime = LocalTime();   return(0); }
这个示例只适用于一个终端的一个智能交易运行。如果一个或多个智能交易同时运行,交易之间的停顿将不会保持在10 秒。当其他智能交易进行交易时,他们没有任何意识。每个智能交易都有自己的 LastTradeTime 变量。从上面我们得出一个很明显的结论: 你应该创建一个整体变量并且记住最近的交易时间。这里我们只的是终端的整体变量,所有的智能交易都将从这里通过。

3. 函数 _PauseBeforeTrade()
虽然代码实现的停顿对于所有的智能交易都是相同的,此函数将会更加合理地安排。将可以提供的智能交易代码的最大可用性和最小成交量。

在开始编写代码之前,让我们一步一步地按照指令执行 - 这样能够减少时间同样可以避免不必要的错误。那么,函数需要做到以下这些:
[*]检测整体变量是否创建。如果没有整体变量,创建它。 从智能交易的init()函数中创建和保存更加符合逻辑,但随后可能被用户删除并且所有的智能交易将在此时停止保持交易之间的停顿。所以我们需要将其放置到函数中创建;[*]记住整体变量中的当前时间 ,使其他的智能交易保持停顿;[*]在最后的交易结束后,检测时间是否够用。为了使用方便,需要添加一个外部变量来设定停顿的持续时间。对于每个智能交易变量值可以改变;[*]显示信息,在运行中程序处理和错误生成;[*]在执行结果中返回不同值.在最后的交易结束后,如果函数探测到时间不足,必须等待。函数Sleep() 将得到函数 IsStopped()的等待和检测值。即 ,如果你从图表“睡眠”状态中删除智能交易,将会强制执行。
对于更多的描述,让它显示需要等待时间的信息("睡眠"状态中每秒)。

以下是我们需要得到的结果:


extern int PauseBeforeTrade = 10; // 交易之间的停顿(以秒为单位) /////////////////////////////////////////////////////////////////////////////////// int _PauseBeforeTrade()//// 对于整体变量LastTradeTime函数设定地方时间值 .// 如果此刻开启的地方时间值小于LastTradeTime + // PauseBeforeTrade 值,函数将进行等待。// 如果根本没有整体变量LastTradeTime, 函数将进行创建.// 返回代码://1 - 成功编译// -1 - 智能交易被用户打断(智能交易从图表中删除, //      终端关闭, 图表货币对或时间周期改变,等等。)/////////////////////////////////////////////////////////////////////////////////int _PauseBeforeTrade() {// 在测试执行期间没有停顿 - 只是终端函数if(IsTesting())
    return(1);   int _GetLastError = 0;int _LastTradeTime, RealPauseBeforeTrade;   //+------------------------------------------------------------------+//| 检测整体变量是否存在。如果不存在,进行创建                               |//+------------------------------------------------------------------+while(true)   {    // 如果智能交易被用户打断,停止运行    if(IsStopped())      {       Print("智能交易被用户终止!");       return(-1);      }    // 检测整体变量是否存在    // 如果存在,循环等待    if(GlobalVariableCheck("LastTradeTime"))       break;    else   // 如果GlobalVariableCheck返回FALSE, 说明没有任何整体变量存在,   // 或是在检测过程中出现了错误   {      _GetLastError = GetLastError();      // 如果仍然存在错误,显示信息,等待0.1秒,       // 开始重新检测      if(_GetLastError != 0)       {      Print("_PauseBeforeTrade()-GlobalVariableCheck(\"LastTradeTime\")-Error #",            _GetLastError );      Sleep(100);      continue;       }   }    // 如果没有错误生成,说明没有整体变量,尝试创建    // 如果GlobalVariableSet > 0, 说明整体变量成功创建.   // 退出函数    if(GlobalVariableSet("LastTradeTime", LocalTime() ) > 0)       return(1);    else   // 如果GlobalVariableSet 返回值<= 0, 说明在变量创建期间生成错误   {      _GetLastError = GetLastError();      // 显示信息,等待0.1秒,重新开始尝试       if(_GetLastError != 0)       {      Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ",               LocalTime(), ") - Error #", _GetLastError );      Sleep(100);      continue;       }   }   }//+--------------------------------------------------------------------------------+//| 如果函数执行达到此点,所名整体变量存在                                                 |//|                                                                              |//| 等待LocalTime() 值> LastTradeTime + PauseBeforeTrade                            |//+--------------------------------------------------------------------------------+while(true)   {    // 如果智能交易被用户打断,停止运作    if(IsStopped())      {       Print("智能交易被用户终止!");       return(-1);      }    // 获取整体变量值   _LastTradeTime = GlobalVariableGet("LastTradeTime");    // 如果此时生成错误,显示信息,等待0.1秒,   // 并且在此尝试    _GetLastError = GetLastError();    if(_GetLastError != 0)   {      Print("_PauseBeforeTrade()-GlobalVariableGet(\"LastTradeTime\")-Error #",             _GetLastError );      continue;   }    // 以秒为单位计算自最后交易结束过去的时间    RealPauseBeforeTrade = LocalTime() - _LastTradeTime;    // 如果少于PauseBeforeTrade秒数的时间过去,    if(RealPauseBeforeTrade < PauseBeforeTrade)   {      // 显示信息,等待一秒,重新检验      Comment("Pause between trades. Remaining time: ",
PauseBeforeTrade - RealPauseBeforeTrade, " sec" );      Sleep(1000);      continue;   }    // 如果过去时间超过PauseBeforeTrade秒数,停止循环    else      break;   }//+--------------------------------------------------------------------------------+//| 如果函数执行到达此点,说明整体变量存在并且地方时间超过LastTradeTime + PauseBeforeTrade   |//|                                                                              |//| 给整体变量LastTradeTime 设置地方时间值                                             |//+--------------------------------------------------------------------------------+while(true)   {    // 如果智能交易被用户打断,停止运作    if(IsStopped())      {       Print("智能交易被用户终止!");       return(-1);   }    // 给整体变量LastTradeTime设置地方时间值。    // 成功的情况下退出    if(GlobalVariableSet( "LastTradeTime", LocalTime() ) > 0)      {       Comment("");       return(1);      }    else    // 如果GlobalVariableSet 返回值<= 0, 说明错误生成   {      _GetLastError = GetLastError();      // 显示信息,等待0.1 秒,并且重新开始尝试      if(_GetLastError != 0)       {      Print("_PauseBeforeTrade()-GlobalVariableSet(\"LastTradeTime\", ",               LocalTime(), " ) - Error #", _GetLastError );      Sleep(100);      continue;       }   }   } }
4. 结合智能交易的使用检测函数,我们创建一个预测智能交易来保持交易之间的停顿。函数 _PauseBeforeTrade() 被放置在PauseBeforeTrade.mq4 的包含文件中,在智能交易直接使用 #include。
注意! 这个智能交易只能用作检测函数的可用性!不能使用在交易中!


#include <PauseBeforeTrade.mq4> int ticket = 0;int start() {// 如果这个智能交易没有开仓if(ticket <= 0)   {    // 保持交易之间停顿,如果有错误生成,退出    if(_PauseBeforeTrade() < 0)
return(-1);    // 刷新市场信息    RefreshRates();   // 尝试开仓    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0,                        Lime);    if(ticket < 0)      Alert("Error OrderSend № ", GetLastError());   }// 如果这个智能交易有开仓else   {    // 保持交易之间的停顿(如果有错误生成,退出)    if(_PauseBeforeTrade() < 0)      return(-1);    // 刷新市场信息    RefreshRates();   // 尝试平仓    if (!OrderClose( ticket, 0.1, Bid, 5, Lime ))      Alert("Error OrderClose № ", GetLastError());    else      ticket = 0;   }return(0); }

随后,一个智能交易获取 EURUSD-M1图表,另一个智能交易获取完全相同的GBPUSD-M1图表。这个结果不会长时间保存: 两个智能交易在交易中保持10秒的停顿:


http://articles.mql4.com/c/articles/2008/03/fig1_2.png



http://articles.mql4.com/c/articles/2008/03/fig2_1.png



5. 可能出现的问题当几个智能交易在一个整体变量上运行时,错误会生成。为了避免错误,我们必须限定变量通道。在文章"错误146 ("交易作业忙")和如何解决"中有一些“限定”的计算描述。这种计算对我们很有用。
智能交易的最终版本如下:


#include <PauseBeforeTrade.mq4>#include <TradeContext.mq4> int ticket = 0;int start() {// 如果这个智能交易没有开仓if(ticket <= 0)   {    // 等待直至交易空闲并占据 (如果有错误生成,   // 退出)    if(TradeIsBusy() < 0)      return(-1);    // 保持交易之间的停顿    if(_PauseBeforeTrade() < 0)   {      // 如果错误生成,交易空闲并退出 TradeIsNotBusy();      return(-1);   }    // 刷新市场信息    RefreshRates();   // 尝试开仓    ticket = OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0, "PauseTest", 123, 0,                        Lime);    if (ticket < 0)      Alert("Error OrderSend № ", GetLastError());    // 交易空闲    TradeIsNotBusy();   }// 如果这个智能交易有开仓else   {    // 等待直至交易空闲并占据(如果错误生成,,   // 退出)    if(TradeIsBusy() < 0)      return(-1);    // 保持交易之间的停顿    if(_PauseBeforeTrade() < 0)   {      // 如果错误生成,交易空闲并退出      TradeIsNotBusy();      return(-1);   }    //刷新市场信息    RefreshRates();   // 尝试平仓    if(!OrderClose( ticket, 0.1, Bid, 5, Lime))      Alert("Error OrderClose № ", GetLastError());    else      ticket = 0;   // 交易空闲    TradeIsNotBusy();   }return(0); }

转自 MetaQuotes Software Corp.
原文: http://articles.mql4.com/ru/103
附件:
http://www.mql4.com/i/ico/unk.gif PauseBeforeTrade.mqh (5.5 Kb)
http://www.mql4.com/i/ico/mq4.gif PauseTest_expert.mq4 (1.9 Kb)
http://www.mql4.com/i/ico/mq4.gif TradeContext.mq4 (7.2 Kb)
创建: 2008.03.28创建人: Andrey Khatimliansky

hefeiddd 发表于 2008-5-25 07:31

智能交易示例 [ en | ru ]http://www.mql4.com/i/print.gif
以 MQL4语言程序为原理展示一个以标准MACD 指标为基础简单的智能交易系统的创建。 在这个智能交易中,我们将看到一些特性的示例,像赢利水平的设定,追踪止损的设置等等。在我们的范例中,通过开仓和管理仓位来完成交易。
交易原理:

[*]Long (BUY) entry – MACD指标在零以下, 从下至上并且穿过低端的信号线。
http://articles.mql4.com/c/articles/2005/12/macd_down(2).gif
[*]Short (SELL) entry – MACD 指标在零以上,从上至下并且穿过顶端的信号线。
http://articles.mql4.com/c/articles/2005/12/macd_up(2).gif
[*]Long exit – 赢利上限的执行,追踪止损的执行或当穿过 MACD 的信号线 (MACD 指标在零以上,从上至下并且穿过顶端的信号线)。
[*]Short exit – 赢利上限的执行,追踪止损的执行或当穿过 MACD 的信号线 (MACD指标在零以下, 从下至上并且穿过低端的信号线)。

重要提示:从我们的分析上排除一些 MACD 指标微不足道的变化 (图表上的小 '山丘'),我们介绍一种补充检测‘山丘’大小的办法如下:指标的大小应该在最低价的最后5个单元(5*Point,对于 USD/CHF = 0.0005 和 USD/JPY = 0.05).


http://articles.mql4.com/c/articles/2005/12/sample(2).gif步骤 1 – 编写智能交易的描述
http://articles.mql4.com/c/articles/2008/03/fig1.png在智能交易的导航窗口处,点击鼠标右键并且选择在菜单中的“创建新智能交易”。创建智能交易的初始提醒将会询问你进入数据中心。在显示窗口,填写智能交易的名称(名称) - MACD Sample,作者(作者) -指出你的名字, 链接 (连接) -你网页的链接,注解 (注解) - MACD-基本智能交易的测试范例。

步骤 2 –创建程序的基本结构
测试智能交易的源代码将只占据一点位置,但是还是有些量经常很难抓住,特别是我们不是专业的编成工作者 - 另外,我们不需要这些描述,不是吗? :)
一个标准智能交易的结构构想,让我们看看以下部分的描述:
[*]初始变量
[*]初始数据检测
[*]检测图表,图表中的柱数
[*]检测外部变量值:标准手, S/L, T/P, T/S
[*]对于快速数据通道设置内部变量
[*]检测交易终端 – 是无效的吗?如果是:
[*]检测: 账户上的可用保证金...
[*]可能是看涨仓位 (BUY)?
[*]开设看涨仓位并退出
[*]可能是卖空仓位 (SELL)?
[*]开设卖空仓位并退出
退出智能交易... [*]周期循环检验先前开仓
[*]如果是看涨仓位
[*]应该平仓?
[*]应该重新设定追踪止损?
[*]如果是卖空仓位
[*]应该平仓?
[*]应该重新设定追踪止损?
返回的结果很简单,只有4种。
现在让我们尝试一步一步地区完成列出的计划:

[*]初始变量
所有使用在智能交易程序中的变量必须按照 MetaQuotes Language 4 要求的指定。这就是为什么我们在程序的开始插入初始变量的原因
extern double TakeProfit = 50;
extern double Lots = 0.1;
extern double TrailingStop = 30;
extern double MACDOpenLevel=3;
extern double MACDCloseLevel=2;
extern double MATrendPeriod=26;

MetaQuotes语言4 是需要“外部变量”辅助的。外部变量可以从外部设定,在智能交易程序源代码设定之后不可以修改。提供一个额外的灵活性。在我们的程序中,MATrendPeriod 变量作为外部变量指定。 在程序开始我们插入这个变量。
extern double MATrendPeriod=26;[*]检测初始数据
该代码部分通常使用在所有的智能交易中。因为是一个标准的检测:
// 初始数据检测
// 确认智能交易运行正常非常重要
//图表和用户设置不能出现任何错误
// 变量(Lots, StopLoss, TakeProfit,
// TrailingStop) 我们的情况需要检测TakeProfit
// 图表中少于100 柱
   if(Bars<100)
   {
      Print("少于 100柱");
      return(0);
   }
   if(TakeProfit<10)
   {
      Print("赢利少于10");
      return(0);// 检测TakeProfit
   }
[*]对于数据的快速通道设置内部变量
在源代码中经常需要注意指标值或计算值。简化代码和数据放置在内部变量中。
int start(){   double MacdCurrent, MacdPrevious, SignalCurrent;   double SignalPrevious, MaCurrent, MaPrevious;   int cnt, ticket, total; // 简化代码//数据放置在内部变量中   MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);现在,用 iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0)代替,您可以在源代码中使用 MacdCurrent。
[*]检测交易终端 –是空的吗?如果是:
在我们的智能交易中,我们仅使用开单和操作挂单。不过,使更安全,我们来认识一种 对于先前定单交易终端检测:

   total=OrdersTotal();
   if(total<1)
   {
[*]检测: 账户上的可用保证金...
在分析市场状况之前,检测你的账户上可用的自由保证金可以开仓。
      if(AccountFreeMargin()<(1000*Lots))
      {
         Print("没有资金.自由保证金 = ", AccountFreeMargin());
         return(0);
      }
[*]可能是看涨仓位 (BUY)?
进入看涨仓位的条件: MACD 低于零, 向上并且穿过信号线向下。这就是我们在 MQL4中描述的 (注意我们在指标上的业务值保存在先前的变量中):
      // 尽可能检测看涨仓位 (BUY)
      if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
         MacdPrevious
         MathAbs(MacdCurrent)>(MACDOpenLevel*Point) &&
         MaCurrent>MaPrevious)
      {
         ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,
                        "macd sample",16384,0,Green);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("BUY 开单 : ",OrderOpenPrice());
         }
         else Print("错误 opening BUY order : ",GetLastError());
         return(0);
      }
附加的检验‘山丘’的大小上面已经给出了描述。 MACDOpenLevel变量是一个用户指定变量,它不可能改变程序文本,但是却有很大的灵活性。在程序开始我们插入这个变量的描述。
[*]可能是卖空仓位(SELL)?
进入卖空仓位的条件: MACD高于零,向上并且穿过信号线向下。注解如下:
      // 尽可能的检测卖空仓位(SELL)
      if(MacdCurrent>0 && MacdCurrentSignalPrevious &&
         MacdCurrent>(MACDOpenLevel*Point) && MaCurrent
      {
         ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,
                        "macd sample",16384,0,Red);
         if(ticket>0)
         {
            if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
               Print("SELL 开单 : ",OrderOpenPrice());
         }
         else Print("错误SELL定单开仓 : ",GetLastError());
         return(0);
      }
return(0);
}[*]周期循环检验先前开仓
//进入市场的正确性非常重要
// 但是更重要的是安全退出...   
for(cnt=0;cnt
{
   OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
   if(OrderType()<=OP_SELL &&   // 检验开仓
      OrderSymbol()==Symbol())// 检验货币对
   {
"cnt" – " 是一个循环的变量必须在程序开始指定如下:
int cnt = 0; [*]如果是看涨仓位
if(OrderType()==OP_BUY)   // 打开看张仓位
{

[*]应该平仓吗?
退出看涨仓位的条件: MACD 穿过信号线, MACD 高于零,向上并穿过信号线向下。
if(MacdCurrent>0 && MacdCurrentSignalPrevious &&
   MacdCurrent>(MACDCloseLevel*Point))
{
   OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); //平仓
   return(0); //退出
}
[*]应该重设追踪止损马?
我们设定追踪止损只有在仓位盈利已经超过追踪水平点,并且新的止损水平点好于先前的水平。
// 检测追踪止损
if(TrailingStop>0)
{               
   if(Bid-OrderOpenPrice()>Point*TrailingStop)
   {
      if(OrderStopLoss()
      {
         OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,
                     OrderTakeProfit(),0,Green);
         return(0);
      }
   }
}
我们停止操作符。
   }[*]如果是卖空仓位
else //卖空仓位
{

[*]应该平仓吗?
退出卖空仓位的条件: MACD穿过信号线,MACD低于零,向上并且穿过信号线向下。
if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
   MacdPrevious(MACDCloseLevel*Point))
{
   OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); //平仓
   return(0); // 退出
}
[*]应该重设追踪止损吗?
我们设定追踪止损只有在仓位盈利已经超过追踪水平点,并且新的止损水平点好于先前的水平。
// 检测追踪止损
if(TrailingStop>0)
{               
   if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
   {
      if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
      {
         OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,
                     OrderTakeProfit(),0,Red);
         return(0);
      }
   }
}
关闭所有残留开仓。
         }
      }
   }
return(0);
}
这样一步一步地编写我们的智能交易...
步骤3 – 集中程序的结果代码
让我们打开智能交易的设定:使用按钮打开"属性..."菜单。在窗口内指定运行参量的外部设定:



http://articles.mql4.com/c/articles/2008/03/properties2.gif从先前部分集中全部代码:
//+------------------------------------------------------------------+
//|                                                MACD Sample.mq4 |
//|                      Copyright &copy; 2005, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
extern
double
TakeProfit = 50;
extern
double
Lots = 0.1;
extern
double
TrailingStop = 30;
extern
double
MACDOpenLevel=3;
extern
double
MACDCloseLevel=2;
extern
double
MATrendPeriod=26;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int
start()
{
double
MacdCurrent, MacdPrevious, SignalCurrent;
   double
SignalPrevious, MaCurrent, MaPrevious;
   int
cnt, ticket, total;
// 检测初始化数据
// 确定智能交易在图表中运行正常非常重要
// 用户在外部变量交易中不会产生任何错误
// 外部变量 (标准手数, 止损,赢利,
// 追踪止损) 在这种情况下,我们检测图表中赢利水平要小于100 柱
if(Bars<100)
{
Print("少于 100柱");
      return(0);
   }
if(TakeProfit<10)
{
Print("赢利少于10");
      return(0);// 检测赢利水平
}
// 简化代码和加速通道
// 数据被放置在内部变量中
MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);
   MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);
   SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);
   SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);
   MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);
   MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);
   total=OrdersTotal();
   if(total<1)
{
// 没有指定开单
if(AccountFreeMargin()<(1000*Lots))
{
Print("没有资金. 自由保证金 = ", AccountFreeMargin());
         return(0);
      }
// 尽可能检测看涨仓位 (BUY)

if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious &&
         MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);
         if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("BUY 定单开仓 : ",OrderOpenPrice());
         }
else
Print("错误BUY定单开仓 : ",GetLastError());
         return(0);
      }
// 尽可能检测卖空仓位(SELL)
if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
         MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)
{
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);
         if(ticket>0)
{
if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES))
Print("SELL 定单开仓 : ",OrderOpenPrice());
         }
else
Print("错误SELL定单开仓 : ",GetLastError());
         return(0);
      }
return(0);
   }
// 正确进入市场很重要,
// 但正确退出市场更重要...   
for(cnt=0;cnt<total;cnt++)
{
OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if(OrderType()<=OP_SELL &&   // 检测开仓
OrderSymbol()==Symbol())
// 检测货币对
{
if(OrderType()==OP_BUY)
// 看涨仓位开仓
{
// 需要平仓吗?
if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious &&
               MacdCurrent>(MACDCloseLevel*Point))
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); //平仓
return(0); // 退出
}
// 检测追踪止损
if(TrailingStop>0)
{
if(Bid-OrderOpenPrice()>Point*TrailingStop)
{
if(OrderStopLoss()<Bid-Point*TrailingStop)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                     return(0);
                  }
}
}
}
else
// 去卖空仓位
{
// 需要平仓吗?
if(MacdCurrent<0 && MacdCurrent>SignalCurrent &&
               MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDCloseLevel*Point))
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,Violet); // 平仓
return(0); //退出
}
// 检测追踪止损
if(TrailingStop>0)
{
if((OrderOpenPrice()-Ask)>(Point*TrailingStop))
{
if((OrderStopLoss()>(Ask+Point*TrailingStop)) || (OrderStopLoss()==0))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+Point*TrailingStop,OrderTakeProfit(),0,Red);
                     return(0);
                  }
}
}
}
}
}
return(0);
}
// 结束
对于最后智能交易的确认,只需要指定外部变量值 "Lots = 1", "Stop Loss (S/L) = 0" (not used), "Take Profit (T/P) = 120" (appropriate for one-hour intervals), "Trailing Stop (T/S) = 30". 当然,你可以使用自己的值。按 "编写"按钮,如果没有任何错误信息出现 (你可以从 MetaEditor的列表中复制), 按 "保存"键保存智能交易。


附件:
http://www.mql4.com/i/ico/mq4.gif MACD Sample.mq4 (3.8 Kb)
创建: 2008.03.17创建人: MetaQuotes Software Corp

hefeiddd 发表于 2008-5-25 07:33

交易中的数学: 交易仓结果的评估 [ en | ru ]http://www.mql4.com/i/print.gif
如果我偶然间打算做傻瓜,那么就叫它美妙地(安全地)进行。
Nassim N. Taleb简介 : 数学 – 科学中的王者数学知识的意义在任意最小的交易容量中是被人们推崇的,这甚至不需要证明。问题在于怎样划分这个最小容量。在交易者自我拓展交易经验的过程中,他们经常通过阅读论坛信息或是书籍信息等渠道。有些书提供读者需求的信息很少,相反地顾及一些其他的学术。我们将在这篇文章中给出一些结果评估和它的注解。
我们从两个中选择较小的危害越来越多世界数学家在交易中取得成功,这个事实就证明了数学的是交易中的一种方法。在这个基础上,就说明交易 – 不仅仅是根据交易规则进行本能地分析。除了这个以外,到现在为止在金融市场上还没有具体的理论描写。金融市场理论的创建就意味着这些市场的死亡,从哲学的观点出发这是种不可融合的矛盾。但如果在我们面前存在这样的问题 – 带着较少的数学知识走进市场或是没有任何数学知识走进市场, -那 我们会从两者种选择较小的危害。我们将选择数学方法评估交易系统。

正常分布下存在怎样的反常性?正常分配的概念是理论上最基础的概念之一。为什么这样讲呢?事实证明在多数的交易过程中存在正常分布。具体地讲是大多数的交易都靠拢正常分配。我们用举例说明。. 假设我们的分布范围间隔在0到100之内。分布范围是指在每个间隔内任何价值概率的下降则影响这个间隔的全部数字。如果概率下降3. 14 (число Pi),那么概率下降数为 77 。现代计算机可以合乎情理给出很好的所有数据。
怎样从这个范围分布得到正常分布?如果 我们每次从范围分布选几个随机数字 (例如,5) 并且发现平均值为五 (这个称为抽样),这样对于大多数新得到的分布将力求正常分布。中心极限定理指出, 它不仅适用于分布不均匀的样本,而且还适用于其它广泛类别的分布。那是因为正常分布的属性非常清晰,就使得很多过程形成一个正常分布便于分析。我们可以通过简单的MQL4语言指标看到中心极限理论的证据。
用不同的N价值放入不同的图表内开始这个指标 (样本数) 可以看到频率分布得很顺畅。
http://articles.mql4.com/c/articles/2007/08/normal_distribution_2.gif
图.1建立正常分布的指标 这里的N 表示我们从pile中取的中间值=5在0到100的间距范围分布内。在上图我们可以看到四个非常相近的图表,如果我们把它们放入相同比例,那就可以得到标准的正常分布。金融市场的价格 (确切地讲是上涨的价格和其他衍生的事物) ,在很大程度上仍然不符合正常分布的计划。对于金融市场概率事件出现得虽小(在 50%左右) ,但仍明显高于正常分布。因此在正常分布的基础上仍然需要记住评估风险。
数与质的转化甚至在很简单的正常分布的模型中我们可以看到,数量的意义。你输入的数据越多,得到的结果就越精确。建议取样的数量最好不要少于30 。就是说 ,我们想要评估交易业务的结果 (例如,测试中的智能交易)。想要统计一些参数系统,交易仓数量若是少于 30是远远不够的。我们分析的寸头越多,这些简单的成功的寸头不是一个可靠交易系统。因此在提供的150个赢利寸头交易系统中,仅评估15个赢利交易。
评估风险 -- 预期值和离差
分布特点的两个重要特点是预期值和离差。标准的正常分布存在预期值等于零。陡峭或是缓坡的正常分布的特点是一种随机变化的预期值。离差则是正好围绕预期值的一种随机变化。
预期值很简单:对于计数集,全部分布值总结,所获得的总数按照数量分开。举例来说, 许多自然数是无限的,但计数,因为每个价值可以比较,其指数。对于不可计数集,可以进行综合。对于评估系列交易寸头中的预期值我们将综合所有寸头结果并且按照寸头数划分。得到的价值就是每个寸头预期平均结果。如果得到的是负值,就是说我们输掉了平均值。
http://articles.mql4.com/c/articles/2007/08/Normal_Distribution.gif
图2正常分布赢利概率图表. 分布差价的衡量是平方偏差的随机值。这个分布特点被称作离差。通常对于随机分布值预期值称为M(X)。这样离差可以写作 D(X) = M((X-M(X))^2 )。离差中的平方根被称为标准离差,简称为希腊字母sigma (σ) 。就是说正常分布的预期值等于零,而标准离差等于1,被称作标准正常分布或是高斯分布(Gaussian distribution)。
标准离差的价值越高,交易的流动资金就越多,那么相对风险就越高。如果存款额预期值(赢利策略)为 $100, 标准离差为 $500, 那么我们赚得美金的风险值要高出总数。通过30 个寸头结果举例说明:
交易数X (结果)1-17.082-41.003147.804-159.965216.97698.307-87.748-27.84912.341048.1411-60.911210.6313-125.4214-27.811588.03
交易数
X (结果)1632.931754.8218-160.1019-83.3720118.4021145.652248.442377.392457.482567.7526-127.1027-70.1828-127.612931.3130-12.55为了能够找到这些寸头的预期值,我们将全部结果划分30 份。得到的中间值为M(X)等于 $4.26。为了能够找到 标准离差, 我们从每个寸头的交易结果中减去平均值,随后找到平方值和总数平方。得到的结果划分为29份(减去一个寸头数)。这样就得到离差 D 等于 9 353.623。 根据离差的根得到标准离差sigma值为 $96.71。
下表是得到的检验数据:
交易数
X
(结果)X-M(X)
(差额)(X-M(X))^2
(差额二次方)1-17.08-21.34455.39562-41.00-45.262 048.46763147.80143.5420 603.73164-159.96-164.2226 968.20845216.97212.7145 245.5441698.3094.048 843.52167-87.74-92.008 464.008-27.84-32.101 030.41912.348.0865.28641048.1443.881 925.454411-60.91-65.174 247.12891210.636.3740.576913-125.42-129.6816 816.902414-27.81-32.071 028.48491588.0383.777 017.41291632.9328.67821.96891754.8250.562 556.313618-160.10-164.3627 014.209619-83.37-87.637 679.016920118.40114.1413 027.939621145.65141.3919 991.13212248.4444.181 951.87242377.3973.135 347.99692457.4853.222 832.36842567.7563.494 030.980126-127.10-131.3617 255.449627-70.18-74.445 541.313628-127.61-131.8717 389.69692931.3127.05731.702530-12.55-16.81282.5761我们得到的结果是预期值为 $4.26,标准偏离为 $96.71。这并不是最佳的风险关系和交易比例。赢利图表显示的结论为:
http://articles.mql4.com/c/articles/2007/08/Profit_Chart_1.gif
图.3 交易的差额图表.偶然地交易? Z-得分假设本身赢利是在一系列交易业务中偶然得到的。花费了大量的时间去找寻的交易系统在实践时间中证明,它确确实实带来了赢利,证明了交易者找到了一个正确的途径。并且现在假设这些全是偶然?这对于新手来说太过特别。不过评估交易结果存在客观因素。这种情况下,正常分布就能够起到援助的作用。
我们不知道每个交易寸头的结果如何。可以说的只有,要么赢利(+),要么亏损(-)。对于每个交易系统赢利和亏损的分布可能是相互交替。例如,在止损停止的时候如果预期赢利低于预期亏损5倍,那么赢利寸头(带有+号)存在的数量应该比亏损寸头(带有—号)要多。Z-得分可以进行评估赢利寸头替换亏损寸头的频繁率。
Z 得分交易系统的计算公式:
Z=(N*(R-0.5)-P)/((P*(P-N))/(N-1))^(1/2)位置:

N – 系列交易总数;
R – 系列交易中赢利和亏损交易总数;
P = 2*W*L;
W –系列交易中赢利寸头总数;
系列交易 - 这种连续的加号 (例如,+++)或是减号 (例如 , --)。 R计算这一系列的总数。
http://articles.mql4.com/c/articles/2007/08/mqlarticimgeng.gif
图.4 两组赢利和亏损对比. 上面就是2006自动交易锦标赛冠军得主智能交易的部分连续赢利和亏损图表。他竞赛账户Z-得分存在 -3,85值,括号中显示的概率为 99.74%。这就说明在这个交易账户上概率 99.74%和Z-счет负值是相互依存的关系:一个赢利使得其他赢利,一个亏损使得其他亏损。那么是这样吗?看过锦标赛的人可能记得 Roman Rich 放置了自己的智能交易 MACD,经常性地同时开放3个寸头。
红色部分显示的是对于正常分布的连续交易的赢利和亏损。我们可以看到,这个连续交易的赢利和亏损相互交替,那么如何衡量呢? Z-得分对于这个问题可以给出答案: 你的连续赢利和亏损是否包含较多或是较少的赢利(或是亏损)系列交易?如果 Z-得分靠近0,就是说交易寸头的分布与正常分布差别。连续寸头Z-得分顺序可以给我们提供互相依存寸头的关系。
另外,根据正常分布 Z值同样可以说明概率偏差 (平均值=0, sigma=1)。如果正常分布随机值概率在±3σ范围内下降相当于99.74 %,那么在这个间隔时间范围内的概率同样是99.74% 。 这就是为什么正常随机值与自己的平均值不能够超出3个sigma的原因。
Z 可以告诉我们依存的类型。肯定说明赢利寸头多于亏损寸头,而否定责说明 – 赢利可能继续赢利,亏损则会继续亏损。下面图表将会解析概率和类型的关系。
Z-得分
概率%概率类型-3.099.73肯定
-2.999.63肯定-2.899.49肯定
-2.799.31肯定-2.699.07肯定-2.598.76肯定-2.095.45肯定-1.586.64不明-1.068.27不明0.00.00不明1.068.27不明1.586.64不明2.095.45否定2.598.76否定2.699.07否定2.799.31否定2.899.49否定2.999.63否定3.099.73否定寸头之间的相互依存是指赢利继续赢利,亏损继续亏损。否定依存是指赢利过后是亏损,亏损过后是赢利。依存关系允许我们调节开仓的大小,甚至可以略过几个仓位。
持限期回报(HPR)Ralph Vince 在"金钱管理数学" 一书中应用了HPR (holding period returns)概念 –在一定时间内持有寸头的赢利。寸头赢利 10% , HPR=1+0.10=1.10。寸头亏损 10%, HPR=1-0. 10=0.90。换种方法你同样可以得到 HPR值, HPR=BalanceClose/BalanceOpen。这样你得到的就不仅仅是寸头的结果还有HPR值。 这样我们可以对独立的交易合约进行对比。其中之一就是持限期回报的平均值 - AHPR (average holding period returns)。
要找到 AHPR,需要将全部 HPR按照寸头数划分。仔细察看下面这30个寸头。账户的初始交易资金为$500。得到新表格:
交易数差额$结果$隐藏差额$HPR1500.00-17.08482.920.96582482.92-41.00441.920.91513441.92147.80589.721.33444589.72-159.96429.760.72885429.76216.97646.731.50496646.7398.30745.031.15207745.03-87.74657.290.88228657.29-27.84629.450.95769629.4512.34641.791.019610641.7948.14689.931.075011689.93-60.91629.020.911712629.0210.63639.651.016913639.65-125.42514.230.803914514.23-27.81486.420.945915486.4288.03574.451.181016574.4532.93607.381.057317607.3854.82662.201.090318662.20-160.10502.100.758219502.10-83.37418.730.834020418.73118.40537.131.282821537.13145.65682.781.271222682.7848.44731.221.070923731.2277.39808.611.105824808.6157.48866.091.071125866.0967.75933.841.078226933.84-127.10806.740.863927806.74-70.18736.560.913028736.56-127.61608.950.826729608.9531.31640.261.051430640.26-12.55627.710.9804AHPR 得出的计算平均值等于 1.0217。换句话讲,我们在每个寸头得到的平均值为 (1.0217-1)*100%=2. 17 % 。那么事实是这样吗? 如果用2.17除以 30,得到 65.1%。 再用初始资金 $500 除以 65. 1%得到 $325.50。这时得到的真正赢利为 (627.71-500)/500*100%=25. 54%。因此, HPR平均数并不是能够完全正确地估测系统。
伴随计算平均数Ralph Vince同时也介绍了几何平均数,称为GHPR (geometric holding period returns)。几何平均数的计算公式如下:
GHPR=(BalanceClose/BalanceOpen)^(1/N)位置:
N – 寸头数额;
BalanceOpen – 账户初始状态;
BalanceClose – 账户结束状态。
如果我们的交易在再次投资的基础上,系统的 GHPR 值越大,获得赢利的值就越高。如果在再次投资的基础上几何平均数的值小于1,说明系统将会亏损。你可以在sashken'а账户历史上看到AHPR 和GHPR之间的差别。他曾经在很长一段时间内成为锦标赛的领跑者。. AHPR=9.98% 但最终的GHPR=-27.68% 。
Sharpe Ratio有效的投资往往是评估离差的好途径。其中之一就表现为Sharpe Ratio。这个函数显示计算平均数 AHPR无风险率(RFR)下跌与HPR顺序的标准离差(SD )之间的关系。一般情况下,在银行的存款额和义务利率的 RFR (Risk Free Rate)相同。在我们的举例中, AHPR=1.0217, 标准离差SD (HPR)为0.17607, RFR=0.
Sharpe Ratio=(AHPR-(1+RFR))/SD位置:
AHPR –一定时间内持有寸头的计算平均数;
RFR – 无风险率;
SD – 标准偏差.
Sharpe Ratio=(1.0217-(1+0))/0.17607=0.0217/0.17607=0.1232。对于正常分布,在±3σ(=SD)范围内平均值为M(X)得到的随机值近 99%。通过以上可以得出结论Sharpe Ratio 超过 3 是一个很好的结果。在图中我们可以看到,如果寸头结果分布正常,那么根据3个sigma 的规定在每个寸头的交易亏损1% Sharpe=3。
http://articles.mql4.com/c/articles/2007/08/Returns_Distribution_1_2.gif
图.5带有1%.亏损概率正常分布交易结果 在参赛者RobinHood的账户可以得到证明: 他的智能交易在 2006自动交易锦标赛中完成了26个寸头的交易, 其中没有一个亏损。Sharpe Ratio显示值为 3.07!
线性回归(LR)和 线性相关函数(CLC)我们同样可以通过其他途径评估交易结果。Sharpe Ratio允许我们估计风险资金运作,但我们也可以尝试来估计平衡曲线平滑度。如果我们在图表中画出每个寸头的关闭差额值,可以得到一条折线。根据上述各点, 我们可以配备一条直线,以便明显显示出我们的方向的转变。我们现在以Hendrick的智能交易Phoenix_4 为范例详细察看。
http://articles.mql4.com/c/articles/2007/08/Balance_Phoenix_1.gif
图.6 Hendrick差额图表 – 2006自动交易锦标赛参赛者 我们必须找到函数a和 b,使这条直线尽量靠近每个点。我们的范例 x 代表寸头数, y则表示关闭交易的差额。
x (交易)y (差额)111 069.50212 213.90313 533.20414 991.90516 598.10618 372.80714 867.50816 416.80918 108.301019 873.601116 321.801217 980.401319 744.501416 199.001517 943.201619 681.001721 471.001823 254.90
x (交易)y (差额)1924 999.402026 781.602128 569.502230 362.002332 148.202428 566.702530 314.102626 687.802728 506.702824 902.202926 711.603023 068.003124 894.103226 672.403328 446.303424 881.603521 342.60


通常用最小二次方的方法找到这条直线。 我们的函数为 а 和 b。对于每个点 x拥有双重意义: y(x)=a*x+b 和差额(x)。差额离差 (x) 来自y(x)可以标记为 d(x)=y(x)-差额(x)。平方离差的总额(SSD)可以用 SD=Summ{d(n)^2}计算。找到直线的 最小二次方就意味着找到了函数 a 和 b的最小 SD 。这就是对于当前的线性回归 (LR,Linear Regression) 。

http://articles.mql4.com/c/articles/2007/08/Balance_big.gif
图.7来自直线y=ax+b的差额离差值 用最小二次方的方法得到直线函数y=a*x+b ,我们就可以估测出金钱上差额值得偏差。如果我们计算d(x)计算平均数, 得到М(d(x))接近零 (具体说是基本上等于零)。这时SD 的SSD 不等于零并且存在中心限定值。在带有直线差额图表SD/(N-2)的平方根显示价差,同时允许在不同初始状态的账户上评估交易系统。这个参数我们称为线性回归的差额标准离差(LR Standard error).
2006自动交易锦标赛前15名的值:
#登陆
LR Standard error, $赢利, $1Rich6 582.6625 175.602ldamiani5 796.3215 628.403GODZILLA2 275.9911 378.704valvk3 938.299 819.405Hendrick3 687.379 732.306bvpbvp9 208.088 236.007Flame2 532.587 676.208Berserk1 943.727 383.709vgc905.106 801.3010RobinHood109.115 643.1011alexgomel763.765 557.5012LorDen1 229.405 247.9013systrad56 239.335 141.1014emil2 667.764 658.2015payday1 686.104 588.90
差额图表中的直线不仅仅可以衡量金钱价值,同样可以衡量绝对价值。对于这个,我们可以使用相关函数。相关函数r 衡量两组数据。这个参数的价值的范围是在-1到 +1之间。如果 r 值等于 +1,就意味着两组数据相同并且是肯定的。
http://articles.mql4.com/c/articles/2007/08/Positive_correlation.gif
图.8 肯定状态范例如果 r 值等于 -1 ,就意味着两组数据呈相反状态并且是否定的。
http://articles.mql4.com/c/articles/2007/08/Negative_Correlation.gif
图.9 否定状态范例.如果 r值等于零,意味着两组数据之间的依存性没有显示。对于这种情况,我们必须确定两组数据相互之间的关系:其中一个取自差额图表,第二个则是在线性回归上的相关点。
http://articles.mql4.com/c/articles/2007/08/Balance_Phoenix_4_1.gif
图.10 差额值和线性回归上的点 在表格中以一下形式呈现:
交易差额线性回归.010 000.0013 616.00111 069.5214 059.78212 297.3514 503.57313 616.6514 947.36415 127.2215 391.14516 733.4115 834.93618 508.1116 278.72714 794.0216 722.50816 160.1417 166.29917 784.7917 610.071019 410.9818 053.861116 110.0218 497.651217 829.1918 941.431319 593.3019 385.221416 360.3319 829.011518 104.5520 272.791619 905.6820 716.581721 886.3121 160.36

交易
差额线性回归
1823 733.7621 604.151925 337.7722 047.942027 183.3322 491.722128 689.3022 935.512230 411.3223 379.292332 197.4923 823.082428 679.1124 266.872529 933.8624 710.652626 371.6125 154.442728 118.9525 598.232824 157.6926 042.012925 967.1026 485.803022 387.8526 929.583124 070.1027 373.373225 913.2027 817.163327 751.8428 260.943423 833.0828 704.733519 732.3129 148.51
差额值用 X表示,在线性回归直线上的连续点用Y表示。要计算出X和 Y的线性相关函数,先要找到平均值M(X)和 M(Y)。随后需要建立新数组T=(X-M(X))*(Y-M(Y)) 并计算 出平均值M(T)=cov(X,Y)=M((X-M(X))*(Y-M(Y)))。得到的价值称为 X 和Y的方差同时也意味着 (X-M(X))*(Y-M(Y))预期值。在我们的范例中方差值 等于21 253 775. 08。 值得注意的是M(X)和 M(Y)平均值相互相等,这样就存在价值21 382.26。就是说,差额平均值和计算直线平均值是相等的。
T=(X-M(X))*(Y-M(Y))M(T)=cov(X,Y)=M((X-M(X))*(Y-M(Y)))位置:
X – 差额;
Y – 线性回归;
M(X)- 差额平均数;
M(Y) – 线性回归平均数。
现在我们来计算 Sx和 Sy值。要计算 Sx需要价值总数 (X-M(X))^2。需要提醒的是用最小二次方计算。将平方总数按照数量划分。我们的例子中划分为36 (0 - 35)。这样我们的Sx 值得到。Sy 值以同样的方法计算。范例中得到的值为Sx=5839,098245,Sy=4610. 181675.
Sx=Summ{(X-M(X))^2}/NSy=Summ{(Y-M(Y))^2}/Nr=cov(X,Y)/(Sx* Sy)位置:
N – 寸头数;
X – 差额;
Y – 线性回归;
M(X)- 差额平均数;
M(Y) – 线性回归平均数。
现在我们就得到了相关函数r=21 253 775.08/(5839. 098245 * 4610.181675)=0.789536583。 这个价值小于1 ,距离0 较远。这种情况下,说明差额图表内趋势线值为0.79。与其他提系统相比较,我们逐步地学习解释相关函数。在 "报告" 里这个参数写作LR correlation。 存在一点不同的是锦标赛中- LR correlation 表示交易赢利。
其实,在差额图表和任意之间的相关函数我们都能够计算。对于锦标赛趋势线相关函数的计算。如果LR correlation 大于0 – 赢利交易,如果小于0 – 亏损交易。有时也会发生有趣的事 - 当账户显示赢利,但LR correlation 却是负值,也可以说是亏损交易。现在我们通过Aver`а的实例情况看看。净赢利总值(Total Net Profit) 为$2 642,而LR сorrelation 值为 -0. 11.。虽然对目前账户没有关联,但这说明我们根本无法判断账户接下来的命运。
参数MAE 和 MFE 告诉我们 我们经常听到这样的话: "减少损失增长利润".看到最后的结果,对于止损或是有效可靠的赢利我们不能够作出任何结论。我们看到的只是开仓时间,平仓时间和最终结果 – 盈利还是亏损。在毫不知晓市场利率浮动的情况,我们不能判定交易系统特性。它的风险是多少?可以达到的赢利值?对于这些问题MAE (Maximum Adverse Excursion) 和 MFE (Maximum Favorable Excursion)参数可以做出很好的回答。
每个寸头从开仓到平仓都会存在利润的波动。在这过程中寸头会达到最大赢利和最大亏损。MFE 显示在有利价位偏差的赢利。然而,MAE 显示在害价位偏差的亏损。这是一个逻辑化的衡量,但如果不同的对货币,我们将不得不表示会应用金钱计算。
每个结束的交易结果与两个参数有关 - MFE 和 MAE。如果交易赢利的结果为 $100, MAE-$1000,这并不代表是最佳值。许多交易赢利,但却存在着相当部分的MAE负值,这就告诉我们系统只是在做休息,接下来的亏损是必然的。
我们同样可以从 MFE值得到信息。如果仓位的方向正确,MFE达到 $3000,但平仓的结果以 $500结束。可以说这是一个不错的保障系统。这个可能是追踪止损(Trailing Stop)。如果短期赢利可以系统化。这个系统可以改善。那么MFE 将会告知。
为了更加便捷地分析可以应用MAE 和 MFE值分布图表。如果我们将每个寸头放入到图表中,就可以明了地看到取得的结果。例如,参赛者RobinHood“报告”没有一个亏损寸头,可以看到其中任意的MAE值从 -$120到 -$2500。
http://articles.mql4.com/c/articles/2007/08/MAE_Distribution.gif
图.11 MAE x Returns的交易分布另外,我们可以得到用最小二次方计算得到的Returns x MAE 交易分布。在上图中以红色显示并向否定方向倾斜 (下降趋势从左到右)。参数 Correlation(Profits, MAE)=-0,59 允许我们对直线附近的点评估,负值显示下降趋势。
如果查看其他参赛者,可以看出相关函数值为肯定。在上面的例子中下降的坡线说明交易呈亏损趋势。现在我们就可以明白理想的LR Correlation值等于1!
同样的方法可以计算 Returns 和MFE分布, 同样找到相关函数Correlation(Profits,MFE)=0.77 和 Correlation(MFE, MAE)=-0.59。函数值Correlation(Profits, MFE) 显示肯定并且接近1 (0.77)。这就告诉我们策略不允许长时间的浮点利率停顿获得赢利。如我们所看到的 MAE 和 MFE分布能够给我们视觉上的评估,相关函数Correlation(Profits, MFE) 和 Correlation(Profits, MAE)能够在没有图表的情况下给出交易信息。
Correlation(MFE, MAE), Correlation(NormalizedProfits, MAE) 和 Correlation(NormalizedProfits, MFE) 值在锦标赛参赛者数据"报告"中作为补充信息。
交易结果正常化通常在交易系统创建中应用固定大小寸头。这样就易于参数的优化。但在找到所需的数据后,就会发现逻辑性的问题:可以接受多大的管理系统(Money Management, MM). 打开交易仓位的大小与账户上的资金存在直接的关系,所以不可能在$5 000 交易占用$50 000美元的仓位。除此之外, ММ系统开仓不一定需要固定比例,就是说如果说存款额为$50 000不是一定要有10个以上以$5 000存款的仓位。
仓位可以根据当前市场状况和分析结果等等进行改变。因此金钱管理系统的最初形态可以替换。那么我们如何估测金钱管理系统带来的影响?对我们的交易系统是正面的还是负面的?在起初相同存款额的几个账户上如何进行对比?简单有效的方法就是将交易结果正常化。
NP=(TradeProfit/TradeLots)*MinimumLots位置:
TradeProfit – 赢利交易;
TradeLots – 交易份额;
MinimumLots – 交易的最小份额。
将交易结果(赢利或是亏损)正常化,我们将交易结果按照交易量划分,随后乘以最小允许交易值。例如,GODZILLA (Nikolay Kositsin)账户,.定单 #4399142 买进2.3标准手USDJPY 赢利 $4 056. 20 + $118.51 (swaps) = $4 174.71平仓。划分结果为2. 3 0.1 (最小允许交易值), 得到赢利$4 056.20/2.3 * 0.1 = $176.36和掉期 = $5.15.。这样得到的结果就是正常化的结果 (Normalized Profits, NP)。
首先,需要找到 Correlation (NormalizedProfits, MAE)值 和Correlation(NormalizedProfits, MFE)值,然后将Correlation(Profits, MAE) 值和 Correlation(Profits, MFE)值进行比较。如果相互之间参数差距较为明显,那我们就不得不改变初始系统。有人说改变金钱管理系统无疑是种自杀,根本不能把亏损交易转为赢利。在锦标赛中 TMR 账户可以说是一个特例,当账户Correlation(NormalizedProfits, MFE) 值从 0.23改变至 0.63仍然保持盈利。
如何估测策略的攻击?我们可以看出正常化交易给金钱管理策略带来有益的影响。非常明显,如果开仓大小增加10倍,自然得到的结果也是最初的10倍。但如果在当前情况增加交易数量呢?得到的结果往往与一种中心模式比较,通常是一种指数。 Beta函数显示交易账户与指数比较改变的次数。
这样,我们首先要计算方差cov(Profits, NormalizedProfits)。随后计算正常化交易离差 ,以作为NP名称。找到以M(NP)命名的正常化交易预期值。 M(NP) 显示正常化交易结果平均值。然后从M(NP)中找到SSD ,就是总值(NP-M(NP))^2。得到的结果按照交易数量划分并称为 D(NP)。这就是正常化交易离差。与正常化交易比较参数结果可以从原始交易结果中估测交易价格波动的次数。在锦标赛 "报告"中这个参数被称为Money Compounding 并且在某种程度上是一种策略攻击。
MoneyCompounding=cov(Profits, NP)/D(NP)=M((Profits-M(Profits))*(NP-M(NP)))/M((NP-M(NP))^2)位置:
Profits – 交易结果;
NP – 正常化的交易结果;
M(NP) – 正常化的交易结果平均数。
现在我们就可以用不同视角看看下表2006自动交易锦标赛参赛者。
#登陆
LR Standard error, $LR CorrelationSharpeGHPRZ-score (%)Money Compounding利润$1Rich6 582.660.810.412.55-3.85(99.74)17.2725 175.602ldamiani5 796.320.640.212.89-2.47 (98.65)28.7915 628.403GODZILLA2 275.990.90.191.970.7(51.61)16.5411 378.704valvk3 938.290.890.221.680.26(20.51)40.179 819.405Hendrick3 687.370.790.241.960.97(66.8)49.029 732.306bvpbvp9 208.080.580.4312.771.2(76.99)50.008 236.007Flame2 532.580.750.363.87-2.07(96.06)6.757 676.208Berserk1 943.720.680.201.590.69(50.98)17.497 383.709vgc905.100.950.291.630.58(43.13)8.066 801.3010RobinHood109.111.003.071.74N/A (N/A)41.875 643.1011alexgomel763.760.950.432.631.52(87.15)10.005 557.5012LorDen1229.400.80.333.061.34(81.98)49.655 247.9013systrad56 239.330.660.272.47-0.9(63.19)42.255 141.1014emil2 667.760.770.211.93-1.97(95.12)12.754 658.2015payday1686.100.750.160.880.46(35.45)10.004 588.90
从上表格中可以看出锦标赛优胜者账户中LR Standard error值并不小。同时,多数赢利智能交易的差额图表都很顺畅。那是因为LR Correlation全部接近 1.0。Sharpe显示的范围在0.20 到 0.40之间。只有一个智能交易Sharpe Ratio=3. 07,说明MAE 和 MFE值不是很好。
GHPR 的基本分配范围在百分之1.5到3 之间。另外优胜者的GHPR 值普遍不大。尽管其中最大的一个GHPR=12. 77% ,再次说明这个账户最大波动LR Standard error=$9 208.08。
在锦标赛前15名的智能交易中Z-得分没有共同点,但 |Z|>2.0值使我们注意到历史交易。我们看到Rich'а 在同时打开三个寸头时 Z=-3,85,而账户 ldamiani的处境呢?
最后,在表格的最后一行为Money Compounding 同样存在很大的范围值从8 到 50。 50 是锦标赛的最大价值,因为锦标赛的规则规定最大交易标准手为5. 0 лота。但奇怪的是优胜者的参数没有这么大,前三名的值分别为17.27, 28.79 和 16.54。难道他们没有完全应用最大允许交易数?不,应用了。那是因为在增加交易买卖同时金钱管理不会提高风险由此我们可以看出金钱管理对于交易系统的重要性。
占据第 15位的智能交易 payday。由于一个小代码的错误,这个智能交易的交易份额不能超过1.0 标准手。如果不是因为这个小代码的错误致使交易份额不可增加到5. 0标准手,那么交易是否赢利值在$4 588.90到$22 944.50之间呢? 要不是挽回风险他会不会取得第二的位置?第一的位置有可能是alexgomel吗?如果他的智能交易的交易份额保持在1.0 标准手。还是 vgc能够取得成功?他的智能交易经常性开仓交易量少于1.0 标准手。看着这些差额图表,仿佛锦标赛仍然在继续,不过它已经成为过去。
结论: 与时俱进见仁见智。这篇文章给出了一些普通的方法估算的交易策略。一个能创造更多的标准来估算交易结果分别采取每个特性将无法提供全面, 客观的估计,但两者融合,他们就可能帮助我们避免片面做法。
可以说,任何肯定的交易结果(连续赢利交易)我们可以从负值交易中获得。这意味着所有这些特征并不能够完全准确地告知交易的薄弱点在贸易。我们应该注意,不应该只满意于最终的肯定结果,得到纯利润就好。
我们不能够创建一个十全十美的智能交易,每个智能交易本身都存在利与弊。懂得估测的方法是不拒绝任何交易方法,而不是教条的执行。要懂得如何能够继续发展智能交易不断更新。上述对2006自动交易锦标赛的统计评论希望对每位交易者都能够带来帮助与支撑。




附件:
http://www.mql4.com/i/ico/mq4.gif NormalDistribution.mq4 (3.3 Kb)
创建: 2007.08.15创建人: Rashid Umarov

hefeiddd 发表于 2008-5-25 07:34

编制自动交易系统的基本知识http://www.mql4.com/i/print.gif

Introduction介绍鉴于许多中国的交易者对交易系统了解不多,本文解释使用MQ4语言编制自动交易系统的基本知识.

Title 编制自动交易系统的基本知识一个交易系统大致包括以下几个方面:
1 开仓策略,即什么条件满足时开仓, 如某条线和某条线上交叉或下交叉,
2 平仓策略,即什么条件满足时平仓, 包括止赢设置,止损设置,和跟踪止赢设置三个方面.
3 资金管理, 其中一个方面就是下单的大小
4 时间管理, 如持仓时间,开平仓时间间隔等
5 账户状态分析,如交易历史,当前资金/仓位/各仓为盈亏状态等.
当然一个交易系统不必包括全部内容,本文做为入门知识也仅通过实例介绍交易系统程序的基本构成.

//+------------------------------------------------------------------+//|                           Designed by OKwh, China               |//|                   Copyright 2007, OKwh Dxdcn                  |//|                                 http://blog.sina.com.cn/FXTrade |
//+------------------------------------------------------------------+
#property
copyright
"Copyright 2007 , Dxd, China."
#property
link
"http://blog.sina.com.cn/FXTrade ,http://www.mql4.com/users/DxdCn"
#define MAGICMA 200610011231//+------------------------------------------------------------------+//| 注意没有指标文件那些property                   |//+------------------------------------------------------------------+extern int whichmethod = 1;   //1~4 种下单方式1 仅开仓, 2 有止损无止赢, 3 有止赢无止损, 4 有止赢也有止损extern double TakeProfit = 100;   //止赢点数extern   double StopLoss = 20;    //止损点数extern double MaximumRisk   = 0.3; //资金控制,控制下单量extern double TrailingStop =25;   //跟踪止赢点数设置extern   int maxOpen = 3;   //最多开仓次数限制 extern   int maxLots = 5;   //最多单仓持仓量限制 extern int bb = 0;       //非零就允许跟踪止赢extern double MATrendPeriod=26;//使用26均线 开仓条件参数本例子 int i, p2, xxx,p1, res;double Lots; datetime lasttime;       //时间控制, 仅当一个时间周期完成才检查条件int init()   //初始化{ Lots = 1;lasttime = NULL;return(0); }int deinit() { return(0); } //反初始化//主程序int start(){CheckForOpen();    //开仓 平仓 条件检查 和操作if (bb>0)   CTP();   //跟踪止赢return(0);}//+------下面是各子程序--------------------------------------------+double LotsOptimized()   //确定下单量,开仓调用 资金控制{double lot=Lots;int   orders=HistoryTotal();   // history orders totalint   losses=0;             // number of losses orders without a break//MarketInfo(Symbol(),MODE_MINLOT);   相关信息//MarketInfo(Symbol(),MODE_MAXLOT);//MarketInfo(Symbol(),MODE_LOTSTEP);lot=NormalizeDouble(MaximumRisk * AccountBalance()/AccountLeverage(),1);   //开仓量计算if(lot<0.1) lot=0.1;if(lot>maxLots) lot=maxLots;return(lot);}//平仓持有的买单void CloseBuy(){if (OrdersTotal( ) > 0 )   {for(i=OrdersTotal()-1;i>=0;i--){if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)   break;if(OrderType()==OP_BUY)   {    OrderClose(OrderTicket(),OrderLots(),Bid,3,White);    Sleep(5000);   }}}}//平仓持有的卖单void CloseSell(){if (OrdersTotal( ) > 0 )   {for(i=OrdersTotal()-1;i>=0;i--){if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)   break;if(OrderType()==OP_SELL)   {    OrderClose(OrderTicket(),OrderLots(),Ask,3,White);    Sleep(5000);   }}}}//判断是否买或卖或平仓int buyorsell()   //在这个函数计算设置你的交易信号这里使用MACD 和MA 做例子{double MacdCurrent, MacdPrevious, SignalCurrent;double SignalPrevious, MaCurrent, MaPrevious;MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious   && MaCurrent>MaPrevious)return (1); // 买 Ma在上升,Macd在0线上,并且两线上交叉if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious   && MaCurrent<MaPrevious)return (-1); // 卖return (0); //不交易}int nowbuyorsell = 0;void CheckForOpen(){if (Time == lasttime ) return; //每时间周期检查一次时间控制lasttime = Time;nowbuyorsell = buyorsell(); //获取买卖信号 if (nowbuyorsell == 1) //买 先结束已卖的CloseSell();if (nowbuyorsell == -1) //卖 先结束已买的    CloseBuy();
if (TimeDayOfWeek(CurTime()) == 1){if (TimeHour(CurTime()) < 3 ) return; //周一早8点前不做 具体决定于你的时区和服务器的时区时间控制}if (TimeDayOfWeek(CurTime()) == 5){if (TimeHour(CurTime()) > 19 ) return; //周五晚11点后不做} if (OrdersTotal( ) >= maxOpen) return ;   //如果已持有开仓次数达到最大,不做if (nowbuyorsell==0) return;   //不交易TradeOK();   //去下单交易}void TradeOK()   //去下单交易{int error ;if (nowbuyorsell == 1) //买   {    switch (whichmethod)    {    case 1:   res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);break;    case 2:   res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-StopLoss*Point,0,"",MAGICMA,0,Blue); break;    case 3:   res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,Ask+TakeProfit*Point,"",MAGICMA,0,Blue);break;    case 4:   res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,Ask-StopLoss*Point,Ask+TakeProfit*Point,"",MAGICMA,0,Blue);break;    default : res=OrderSend(Symbol(),OP_BUY,LotsOptimized(),Ask,3,0,0,"",MAGICMA,0,Blue);break;    }    if (res <=0)    {    error=GetLastError();    if(error==134)Print("Received 134 Error after OrderSend() !! ");         // not enough money    if(error==135) RefreshRates();   // prices have changed    }    Sleep(5000);   return ;   }if (nowbuyorsell == -1) //卖{    switch (whichmethod)    {    case 1:   res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red); break;    case 2:   res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+StopLoss*Point,0,"",MAGICMA,0,Red); break;    case 3:   res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,Bid-TakeProfit*Point,"",MAGICMA,0,Red); break;    case 4:   res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,Bid+StopLoss*Point,Bid-TakeProfit*Point,"",MAGICMA,0,Red); break;    default : res=OrderSend(Symbol(),OP_SELL,LotsOptimized(),Bid,3,0,0,"",MAGICMA,0,Red); break;    }    if (res <=0)    {    error=GetLastError();    if(error==134) Print("Received 134 Error after OrderSend() !! ");         // not enough money    if(error==135) RefreshRates();   // prices have changed    }    Sleep(5000);    return ;   }}void CTP()   //跟踪止赢{bool bs = false;for (int i = 0; i < OrdersTotal(); i++){if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)   break;if (OrderType() == OP_BUY)   {    if ((Bid - OrderOpenPrice()) > (TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))    //开仓价格 当前止损和当前价格比较判断是否要修改跟踪止赢设置    {    if (OrderStopLoss() < Bid - TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT))   {      bs = OrderModify(OrderTicket(), OrderOpenPrice(), Bid - TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(),0, Green);    }    }}   else if (OrderType() == OP_SELL)   {    if ((OrderOpenPrice() - Ask) > (TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))//开仓价格 当前止损和当前价格比较判断是否要修改跟踪止赢设置    {    if ((OrderStopLoss()) > (Ask + TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT)))    {         bs = OrderModify(OrderTicket(), OrderOpenPrice(),      Ask + TrailingStop * MarketInfo(OrderSymbol(), MODE_POINT), OrderTakeProfit(),0, Tan);}    }}}}
Conclusion 结论本例 介绍了自动交易系统程序文件的基本构成, 略加修改就可以用于建立你自己系统.
比如根据你的下单策略修改buyorSell()函数.

注: 本人2006比赛的系统就是这样的框架, 2007 比赛当然也将是这样的框架

创建: 2007.10.23创建人: XDXD

hefeiddd 发表于 2008-5-25 07:35

简单的订单管理 [ en | ru ]http://www.mql4.com/i/print.gif

1. 介绍
每个智能交易程序里都有一段代码是控制建仓的。它在所有的定单中不断搜索,通过信息选择仓位,然后进行修改和关闭。这段代码看上去都差不多,并且往往具有相同的功能。这就是为什么这段经常被重复的代码可以从程序中提取出来成为函数,从而使程序更易写更简洁。 首先,我们按功能把任务分成三个步骤 — 这三个步骤其实是三种智能交易程序:
[*]智能交易程序在同一时间只能新建一个仓位[*]智能交易程序在同一时间可以新建每个类型的一个仓位(比如, 多头和空头的仓位)[*]智能交易程序可以同时新建多个仓位
2. 一个仓位

只新建一个仓位有许多中策略。这种控制代码块非常简单,但写出来也会耗费一定的时间和精力。

举一个简单的例子,一个来自于 MACD 线交叉点(信号线和基础线)的建仓信号,简化它的控制代码块,程序如下:

extern int_MagicNumber = 1122; int start(){    //---- 记住指标值做分析数据    double MACD_1 = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE,                        MODE_MAIN, 1 );    double MACD_2 = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE,                        MODE_MAIN, 2 );   int _GetLastError = 0, _OrdersTotal = OrdersTotal();    //---- 在开仓位置搜索    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {// 如果在搜索中生成错误,转至下一个仓位      if ( !OrderSelect( z, SELECT_BY_POS ) )      {          _GetLastError = GetLastError();          Print("OrderSelect( ", z, ", SELECT_BY_POS ) - 错误 #",                _GetLastError );            continue;      } // 如果当前的货币对没有开仓, // 忽略过      if ( OrderSymbol() != Symbol() ) continue; // 如果 MagicNumber不等于_MagicNumber, // 忽略这个仓位      if ( OrderMagicNumber() != _MagicNumber ) continue;         //---- 如果BUY舱位开仓,      if ( OrderType() == OP_BUY )      {            //---- 如果MACD 遇到下降的零线,            if(NormalizeDouble(MACD_1, Digits + 1) <0.0 &&                NormalizeDouble( MACD_2, Digits + 1) >= 0.0)            {                //---- 平仓                if(!OrderClose( OrderTicket(), OrderLots(),                  Bid, 5, Green))                {                   _GetLastError = GetLastError();                   Alert("错误OrderClose 鈩?", _GetLastError);                   return(-1);                }            }// 如果信号线没有改变,退出:// 开新仓位过早            else            { return(0); }      }      //---- 如果 SELL 仓位开仓,      if ( OrderType() == OP_SELL )      {            //---- 如果 MACD 遇到上升的零线            if(NormalizeDouble(MACD_1, Digits + 1) >0.0 &&                NormalizeDouble(MACD_2, Digits + 1 ) <= 0.0)            {            //---- 平仓            if(!OrderClose( OrderTicket(), OrderLots(),                  Ask, 5, Red))            {                _GetLastError = GetLastError();                Alert( "错误 OrderClose 鈩?", _GetLastError );                return(-1);            }            }// 如果信号没有给便,退出:// 开新仓位过早            else return(0);      }    } //+------------------------------------------------------------------+//|如果达到此点,说明没有开仓仓位                                          |//| 检测可能开仓                                                       |//+------------------------------------------------------------------+   //---- 如果 MACD 遇到上升的零线,    if ( NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0    )    {      //---- 打开 BUY 仓位      if(OrderSend( Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0,            "MACD_test", _MagicNumber, 0, Green ) < 0)      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend 鈩?", _GetLastError );            return(-1);      }      return(0);    }    //---- 如果MACD 遇到下降的零线,      if(NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0)    {      //---- open a SELL position      if(OrderSend( Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0,         "MACD_test",               _MagicNumber, 0, Red ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend 鈩?", _GetLastError );            return(-1);      }      return(0);    }   return(0);}
现在我们把代码块写成函数。这个函数能够在所有的定单中搜索出需要的,并将其信息记录在全局变量中,程序如下:

int _Ticket = 0, _Type = 0; double _Lots = 0.0, _OpenPrice = 0.0, _StopLoss = 0.0;double _TakeProfit = 0.0; datetime _OpenTime = -1; double _Profit = 0.0, _Swap = 0.0;double _Commission = 0.0; string _Comment = ""; datetime _Expiration = -1; void OneOrderInit( int magic ){    int _GetLastError, _OrdersTotal = OrdersTotal();   _Ticket = 0; _Type = 0; _Lots = 0.0; _OpenPrice = 0.0; _StopLoss = 0.0;    _TakeProfit = 0.0; _OpenTime = -1; _Profit = 0.0; _Swap = 0.0;    _Commission = 0.0; _Comment = ""; _Expiration = -1;   for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      if ( !OrderSelect( z, SELECT_BY_POS ) )      {          _GetLastError = GetLastError();          Print("OrderSelect( ", z, ", SELECT_BY_POS ) -错误#",               _GetLastError );          continue;      }      if(OrderMagicNumber() == magic && OrderSymbol() ==            Symbol())      {          _Ticket    = OrderTicket();          _Type      = OrderType();          _Lots      = NormalizeDouble( OrderLots(), 1 );          _OpenPrice = NormalizeDouble( OrderOpenPrice(), Digits);          _StopLoss = NormalizeDouble( OrderStopLoss(), Digits);          _TakeProfit = NormalizeDouble( OrderTakeProfit(), Digits);          _OpenTime   = OrderOpenTime();          _Profit   = NormalizeDouble( OrderProfit(), 2 );          _Swap       = NormalizeDouble( OrderSwap(), 2 );          _Commission = NormalizeDouble( OrderCommission(), 2 );          _Comment    = OrderComment();          _Expiration = OrderExpiration();          return;      }    }}
如你所见,这非常简单: 一共 11 个变量,每个都储存仓位的相关信息(ticket #, type, lot size, 等等). 当函数开始运行时,这些变量被归零。作为全局变量这是必需的。函数被调用时变量也可以不归零,但我们需要的不是先前的信息,我们需要的是最近的。然后所有的仓位会以标准的方式被搜索,一旦获得需要的信号和MagicNumber 值,信息将被存储在相应的变量中。

现在我们将函数用到智能交易程序中:

extern int_MagicNumber = 1122; #include <OneOrderControl.mq4> int start(){    int _GetLastError = 0;    // 记住开仓的参量(如果可用)    OneOrderInit( _MagicNumber );   //---- 记住指标值用作分析    double MACD_1 = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE,                           MODE_MAIN, 1 );    double MACD_2 = iMACD(Symbol(), 0, 12, 26, 9, PRICE_CLOSE,                           MODE_MAIN, 2 );   // 现在,代替在仓位中的搜索   // 存在开仓:    if ( _Ticket > 0 )    {      //----如果BUY 仓位开仓,      if ( _Type == OP_BUY )      {            //---- 如果MACD 遇到下降的零线,             if(NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&                NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0)            {                //---- 平仓                if(!OrderClose( _Ticket, _Lots, Bid, 5, Green))                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose 鈩?", _GetLastError);                  return(-1);                }            }            // 如果信号没有改变,退出:             // 开新仓位过早            else return(0);      }      //----如果 SELL 仓位开仓,      if ( _Type == OP_SELL )      {            //---- 如果MACD 遇到上升的零线            if(NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&                NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0)            {                //---- 平仓                if(!OrderClose( _Ticket, _Lots, Ask, 5, Red))                {                  _GetLastError = GetLastError();                  Alert( "错误 OrderClose 鈩?", _GetLastError);                  return(-1);                }            }            // 如果信号没有改变,退出:             // 开新仓位过早            else return(0);      }    }    // 如果智能交易没有开仓    // ( _Ticket == 0 )    // 如果MACD 遇到上升的零线    if(NormalizeDouble( MACD_1, Digits + 1 ) >0.0 &&      NormalizeDouble( MACD_2, Digits + 1 ) <= 0.0)    {      //---- 开BUY 仓位      if(OrderSend(Symbol(), OP_BUY, 0.1, Ask, 5, 0.0, 0.0,         "CrossMACD", _MagicNumber, 0, Green ) < 0)      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend 鈩?", _GetLastError );            return(-1);      }      return(0);    }    //---- 如果MACD 遇到下降的零线 if ( NormalizeDouble( MACD_1, Digits + 1 ) <0.0 &&         NormalizeDouble( MACD_2, Digits + 1 ) >= 0.0    )    {      //---- 开SELL仓位      if(OrderSend(Symbol(), OP_SELL, 0.1, Bid, 5, 0.0, 0.0,         "CrossMACD",               _MagicNumber, 0, Red ) < 0 )      {            _GetLastError = GetLastError();            Alert( "错误 OrderSend 鈩?", _GetLastError );            return(-1);      }      return(0);    }   return(0);}
如你所见,这段智能交易的程序显得更紧凑更易读。这是一个简单例子。

现在让我们解决下一个任务。
3. 每个类型的一个仓位

我们需要一个更复杂的智能交易程序来实现一些其它的功能。此程序能够新建许多不同类型的仓位,并进行操作。以下是这种程序的规则:
[*]该程序运行时将设置两个待办定单: 在卖出价+20点设置买入止损,在买入价+20点设置卖出止损;[*]当一个定单引发,另一个必须被取消;[*]建仓必须伴随追踪止损;[*]当仓位由于止损或盈利被关闭后,将被再次启动,也就是说两个待办定单将被设置。程序如下:

extern int    _MagicNumber = 1123; extern double Lot          = 0.1;extern int    StopLoss   = 60;    // 止损点的间距 (0 - 无)extern int    TakeProfit   = 100;   // 赢利点的间距 (0 - 无)extern int    TrailingStop = 50;    // 追踪止损点 (0 - 无) extern int    Luft         = 20;    // 挂单交易放置水平的间距int start(){// 记住定单中每个票据    int BuyStopOrder = 0, SellStopOrder = 0, BuyOrder = 0,   SellOrder = 0;    int _GetLastError = 0, _OrdersTotal = OrdersTotal();// 在所有的开仓仓位搜索并记住// 开仓仓位已存在的类型:    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      // 如果在搜索中生成错误,          // 转至下一个仓位      if ( !OrderSelect( z, SELECT_BY_POS ) )      {          _GetLastError = GetLastError();          Print("OrderSelect(", z, ", SELECT_BY_POS) - Error #",               _GetLastError );          continue;      } // 如果当前货币对没有开仓仓位,忽略它 if ( OrderSymbol() != Symbol() ) continue; // 如果MagicNumber 不等于 _MagicNumber, // 忽略这个仓位      if ( OrderMagicNumber() != _MagicNumber ) continue;         // 取决于仓位类型,      // 改变变量值:      switch ( OrderType() )      {          case OP_BUY:      BuyOrder      = OrderTicket(); break;          case OP_SELL:   SellOrder   = OrderTicket(); break;          case OP_BUYSTOP:BuyStopOrder= OrderTicket(); break;          case OP_SELLSTOP: SellStopOrder = OrderTicket(); break;      }    }   //---- 如果我们有两个挂单交易,退出    //---- 等待他们开启    if ( BuyStopOrder > 0 && SellStopOrder > 0 ) return(0);   // 在全部定单中第二次搜索   // 现在运行它们:    _OrdersTotal = OrdersTotal();    for ( z = _OrdersTotal - 1; z >= 0; z -- )    {      // 如果在仓位搜索中生成错误,      // 转至下一个仓位      if ( !OrderSelect( z, SELECT_BY_POS ) )      {            _GetLastError = GetLastError();            Print("OrderSelect(", z, ", SELECT_BY_POS) - 错误 #",                   _GetLastError );            continue;      }         // 如果对于当前的货币对没有开仓      // 忽略它      if ( OrderSymbol() != Symbol() ) continue;         // 如果 MagicNumber 不等于 _MagicNumber,         // 忽略这个仓位      if ( OrderMagicNumber() != _MagicNumber ) continue;         // 取决于仓位的类型,         // 改变变量值:      switch ( OrderType() )      {            //----如果BUY仓位开仓,            case OP_BUY:            {                // 如果 SellStop定单还没有删除,               // 删除:                if ( SellStopOrder > 0 )                {                  if ( !OrderDelete( SellStopOrder ) )                  {                  Alert(OrderDelete Error #", GetLastError());                  return(-1);                  }                }                // 检测止损被移动:                // 如果追踪止损的大小不是很小,                if(TrailingStop > MarketInfo( Symbol(),                  MODE_STOPLEVEL ) )                {                  // 如果赢利点超过追踪止损点,                  if(NormalizeDouble( Bid - OrderOpenPrice(),                        Digits ) >                        NormalizeDouble(TrailingStop*Point,                        Digits ) )                  {                        // 如果新的止损水平超过当前仓位的水平                         // (或者如果仓位没有止损),                        if(NormalizeDouble(Bid -                            TrailingStop*Point, Digits ) >                            OrderStopLoss() || OrderStopLoss() <=                            0.0 )                        {                            //---- 修改定单                            if(!OrderModify( OrderTicket(),                              OrderOpenPrice(),                              NormalizeDouble(Bid -                              TrailingStop*Point, Digits ),                              OrderTakeProfit(),                              OrderExpiration()))                            {                              Alert("OrderModify 错误 #",                                     GetLastError());                              return(-1);                            }                        }                                        }                }                // 如果没有开仓仓位,退出               // 无事可做                return(0);            }            // 下一个单元格与BUY 仓位的单元个一样            // 这就是我们不能在单元格上标注的原因...            case OP_SELL:            {                if ( BuyStopOrder > 0 )                {                  if ( !OrderDelete( BuyStopOrder ) )                  {                        Alert("OrderDelete 错误 #",                               GetLastError());                        return(-1);                  }                }                if(TrailingStop > MarketInfo( Symbol(),                  MODE_STOPLEVEL ) )                {                  if(NormalizeDouble(OrderOpenPrice() - Ask,                   Digits) > NormalizeDouble(TrailingStop*Point,                   Digits ) )                  {                      if(NormalizeDouble(Ask + TrailingStop*Point,                        Digits ) < OrderStopLoss() ||                        OrderStopLoss() <= 0.0 )                        {                        if(!OrderModify( OrderTicket(),                              OrderOpenPrice(),                     NormalizeDouble(Ask + TrailingStop*Point,                           Digits), OrderTakeProfit(),                           OrderExpiration() ) )                            {                              Alert("OrderModify Error #",                                     GetLastError());                              return(-1);                            }                        }                                        }                }                return(0);            }      }    }//+------------------------------------------------------------------+//| 如果执行达到此点,                                                   |//| 说明没有挂单和开仓。                                                 |//+------------------------------------------------------------------+//---- 放置BuyStop 和 SellStop:    double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel;    _OpenPriceLevel = NormalizeDouble( Ask + Luft*Point, Digits );   if ( StopLoss > 0 )    { _StopLossLevel = NormalizeDouble( _OpenPriceLevel -                        StopLoss*Point, Digits ); }    else    { _StopLossLevel = 0.0; }   if ( TakeProfit > 0 )    { _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel +                        TakeProfit*Point, Digits ); }    else    { _TakeProfitLevel = 0.0; }   if ( OrderSend ( Symbol(), OP_BUYSTOP, Lot, _OpenPriceLevel,         5, _StopLossLevel, _TakeProfitLevel, "",          _MagicNumber ) < 0 )    {      Alert( "OrderSend Error #", GetLastError() );      return(-1);    }      _OpenPriceLevel = NormalizeDouble(Bid - Luft*Point, Digits);   if ( StopLoss > 0 )    { _StopLossLevel = NormalizeDouble( _OpenPriceLevel +                        StopLoss*Point, Digits ); }    else    { _StopLossLevel = 0.0; }   if ( TakeProfit > 0 )    { _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel -                        TakeProfit*Point, Digits ); }    else    { _TakeProfitLevel = 0.0; }   if ( OrderSend ( Symbol(), OP_SELLSTOP, Lot, _OpenPriceLevel,          5, _StopLossLevel,                  _TakeProfitLevel, "", _MagicNumber ) < 0 )    {      Alert( "OrderSend Error #", GetLastError() );      return(-1);    }   return(0);}
现在让我们写出可以简化控制建仓代码的函数,它必须用每个类型的定单进行搜索,然后将这些信息存储在全局变量里,程序如下:


// 在定单特性中的整体变量会被储存:int _BuyTicket = 0, _SellTicket = 0, _BuyStopTicket = 0;int _SellStopTicket = 0, _BuyLimitTicket = 0, _SellLimitTicket = 0; double _BuyLots = 0.0, _SellLots = 0.0, _BuyStopLots = 0.0; double _SellStopLots = 0.0, _BuyLimitLots = 0.0, _SellLimitLots = 0.0; double _BuyOpenPrice = 0.0, _SellOpenPrice = 0.0, _BuyStopOpenPrice = 0.0;double _SellStopOpenPrice = 0.0, _BuyLimitOpenPrice = 0.0, _SellLimitOpenPrice = 0.0; double _BuyStopLoss = 0.0, _SellStopLoss = 0.0, _BuyStopStopLoss = 0.0;double _SellStopStopLoss = 0.0, _BuyLimitStopLoss = 0.0, _SellLimitStopLoss = 0.0; double _BuyTakeProfit = 0.0, _SellTakeProfit = 0.0, _BuyStopTakeProfit = 0.0;double _SellStopTakeProfit = 0.0, _BuyLimitTakeProfit = 0.0, _SellLimitTakeProfit = 0.0; datetime _BuyOpenTime = -1, _SellOpenTime = -1, _BuyStopOpenTime = -1;datetime _SellStopOpenTime = -1, _BuyLimitOpenTime = -1, _SellLimitOpenTime = -1; double _BuyProfit = 0.0, _SellProfit = 0.0, _BuySwap = 0.0, _SellSwap = 0.0;double _BuyCommission = 0.0, _SellCommission = 0.0; string _BuyComment = "", _SellComment = "", _BuyStopComment = ""; string _SellStopComment = "", _BuyLimitComment = "", _SellLimitComment = ""; datetime _BuyStopExpiration = -1, _SellStopExpiration = -1;datetime _BuyLimitExpiration = -1, _SellLimitExpiration = -1; void OneTypeOrdersInit( int magic ){// 变量归零:    _BuyTicket = 0; _SellTicket = 0; _BuyStopTicket = 0;    _SellStopTicket = 0; _BuyLimitTicket = 0; _SellLimitTicket = 0;   _BuyLots = 0.0; _SellLots = 0.0; _BuyStopLots = 0.0;   _SellStopLots = 0.0; _BuyLimitLots = 0.0; _SellLimitLots = 0.0;   _BuyOpenPrice = 0.0; _SellOpenPrice = 0.0; _BuyStopOpenPrice = 0.0;    _SellStopOpenPrice = 0.0; _BuyLimitOpenPrice = 0.0; _SellLimitOpenPrice = 0.0;   _BuyStopLoss = 0.0; _SellStopLoss = 0.0; _BuyStopStopLoss = 0.0;    _SellStopStopLoss = 0.0; _BuyLimitStopLoss = 0.0; _SellLimitStopLoss = 0.0;   _BuyTakeProfit = 0.0; _SellTakeProfit = 0.0; _BuyStopTakeProfit = 0.0;    _SellStopTakeProfit = 0.0; _BuyLimitTakeProfit = 0.0; _SellLimitTakeProfit = 0.0;   _BuyOpenTime = -1; _SellOpenTime = -1; _BuyStopOpenTime = -1;    _SellStopOpenTime = -1; _BuyLimitOpenTime = -1; _SellLimitOpenTime = -1;   _BuyProfit = 0.0; _SellProfit = 0.0; _BuySwap = 0.0; _SellSwap = 0.0;    _BuyCommission = 0.0; _SellCommission = 0.0;   _BuyComment = ""; _SellComment = ""; _BuyStopComment = "";   _SellStopComment = ""; _BuyLimitComment = ""; _SellLimitComment = "";   _BuyStopExpiration = -1; _SellStopExpiration = -1;    _BuyLimitExpiration = -1; _SellLimitExpiration = -1;   int _GetLastError = 0, _OrdersTotal = OrdersTotal();    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      if ( !OrderSelect( z, SELECT_BY_POS ) )      {          _GetLastError = GetLastError();          Print("OrderSelect(", z, ",SELECT_BY_POS) - Error #",               _GetLastError );          continue;      }      if ( OrderMagicNumber() == magic && OrderSymbol() ==             Symbol() )      {          switch ( OrderType() )          {            case OP_BUY:             _BuyTicket   = OrderTicket();             _BuyLots       = NormalizeDouble( OrderLots(), 1 );             _BuyOpenPrice= NormalizeDouble( OrderOpenPrice(),                                             Digits );             _BuyStopLoss   = NormalizeDouble( OrderStopLoss(),                                                Digits );             _BuyTakeProfit = NormalizeDouble( OrderTakeProfit(),                                             Digits );             _BuyOpenTime   = OrderOpenTime();             _BuyProfit   = NormalizeDouble( OrderProfit(), 2 );             _BuySwap       = NormalizeDouble( OrderSwap(), 2 );             _BuyCommission = NormalizeDouble( OrderCommission(),                                             2 );             _BuyComment    = OrderComment();             break;         case OP_SELL:             _SellTicket   = OrderTicket();             _SellLots       = NormalizeDouble( OrderLots(), 1 );             _SellOpenPrice= NormalizeDouble( OrderOpenPrice(),                                                Digits );             _SellStopLoss   = NormalizeDouble( OrderStopLoss(),                                                Digits );             _SellTakeProfit = NormalizeDouble( OrderTakeProfit(),                                                Digits );             _SellOpenTime   = OrderOpenTime();             _SellProfit   = NormalizeDouble( OrderProfit(), 2 );             _SellSwap       = NormalizeDouble( OrderSwap(), 2 );             _SellCommission = NormalizeDouble( OrderCommission(),                                                2 );             _SellComment    = OrderComment();             break;         case OP_BUYSTOP:             _BuyStopTicket   = OrderTicket();             _BuyStopLots       = NormalizeDouble( OrderLots(), 1 );             _BuyStopOpenPrice= NormalizeDouble( OrderOpenPrice(),                                                   Digits );             _BuyStopStopLoss   = NormalizeDouble( OrderStopLoss(),                                                   Digits );             _BuyStopTakeProfit = NormalizeDouble( OrderTakeProfit(),                                                   Digits );             _BuyStopOpenTime   = OrderOpenTime();             _BuyStopComment    = OrderComment();             _BuyStopExpiration = OrderExpiration();             break;          case OP_SELLSTOP:             _SellStopTicket   = OrderTicket();             _SellStopLots       = NormalizeDouble( OrderLots(), 1 );             _SellStopOpenPrice= NormalizeDouble( OrderOpenPrice(),                                                    Digits );             _SellStopStopLoss   = NormalizeDouble( OrderStopLoss(),                                                    Digits );             _SellStopTakeProfit = NormalizeDouble( OrderTakeProfit(),                                                    Digits );             _SellStopOpenTime   = OrderOpenTime();             _SellStopComment    = OrderComment();             _SellStopExpiration = OrderExpiration();             break;          case OP_BUYLIMIT:             _BuyLimitTicket   = OrderTicket();             _BuyLimitLots       = NormalizeDouble( OrderLots(), 1 );             _BuyLimitOpenPrice= NormalizeDouble( OrderOpenPrice(),                                                    Digits );             _BuyLimitStopLoss   = NormalizeDouble( OrderStopLoss(),                                                    Digits );             _BuyLimitTakeProfit = NormalizeDouble( OrderTakeProfit(),                                                    Digits );             _BuyLimitOpenTime   = OrderOpenTime();             _BuyLimitComment    = OrderComment();             _BuyLimitExpiration = OrderExpiration();             break;         case OP_SELLLIMIT:             _SellLimitTicket   = OrderTicket();             _SellLimitLots       = NormalizeDouble( OrderLots(), 1 );             _SellLimitOpenPrice= NormalizeDouble( OrderOpenPrice(),                                                   Digits );             _SellLimitStopLoss   = NormalizeDouble( OrderStopLoss(),                                                   Digits );             _SellLimitTakeProfit = NormalizeDouble( OrderTakeProfit(),                                                   Digits );             _SellLimitOpenTime   = OrderOpenTime();             _SellLimitComment    = OrderComment();             _SellLimitExpiration = OrderExpiration();             break;            }      }    }}
现在我们将函数用到智能交易程序中:


extern int    _MagicNumber = 1123;extern double Lot          = 0.1;extern int    StopLoss   = 60;    // 止损点的间距(0 - d无)extern int    TakeProfit   = 100;   // 赢利点的间距 (0 - 无)extern int    TrailingStop = 50;    //追踪止损点 (0 - 无) extern int    Luft         = 20;    // 挂单交易放置水平的间距 #include <OneTypeOrdersControl.mq4> int start(){    int _GetLastError = 0;   //---- 记住开仓的参量(如果可用)    OneTypeOrdersInit( _MagicNumber );   //---- 如果我们两个都是挂单交易,退出   //---- 等待他们开启    if ( _BuyStopTicket > 0 && _SellStopTicket > 0 ) return(0);   //---- 如果 BUY 仓位开仓    if ( _BuyTicket > 0 )    {      //---- 如果SellStop 还没有删除,删除它:      if ( _SellStopTicket > 0 )      {            if ( !OrderDelete( _SellStopTicket ) )            {                Alert( "OrderDelete 错误#", GetLastError() );                return(-1);            }      }      //---- 检测止损被移动:      //---- 如果追踪止损不是很小,      if ( TrailingStop > MarketInfo( Symbol(),            MODE_STOPLEVEL ) )      {//---- 如果赢利仓位超过追踪止损点,            if ( NormalizeDouble( Bid - _BuyOpenPrice, Digits ) >                   NormalizeDouble( TrailingStop*Point, Digits ) )            {//---- 如果新止损水平超过当前仓位//---- (或者当前仓位没有止损),                if(NormalizeDouble( Bid - TrailingStop*Point,                  Digits ) > _BuyStopLoss                   || _BuyStopLoss <= 0.0 )                {                  //---- 修改定单                  if ( !OrderModify( _BuyTicket, _BuyOpenPrice,                           NormalizeDouble( Bid - TrailingStop*Point,                        Digits ),                           _BuyTakeProfit, 0 ) )                  {                        Alert( "OrderModify 错误#",                              GetLastError() );                        return(-1);                  }                }                              }      }//---- 如果没有开仓仓位,退出,无事可做      return(0);    } //---- 这个单元格与BUY仓位的单元格相似//---- 这就是我们不能做标注的原因...    if ( _SellTicket > 0 )    {      if ( _BuyStopTicket > 0 )      {            if ( !OrderDelete( _BuyStopTicket ) )            {                Alert( "OrderDelete错误 #", GetLastError() );                return(-1);            }      }      if(TrailingStop > MarketInfo( Symbol(), MODE_STOPLEVEL))      {            if(NormalizeDouble( _SellOpenPrice - Ask, Digits ) >                  NormalizeDouble( TrailingStop*Point, Digits ) )            {                if(NormalizeDouble( Ask + TrailingStop*Point,                  Digits ) < _SellStopLoss                      || _SellStopLoss <= 0.0 )                {                  if(!OrderModify( _SellTicket, _SellOpenPrice,                        NormalizeDouble( Ask + TrailingStop*Point,                        Digits ),                        _SellTakeProfit, 0 ) )                  {                        Alert( "OrderModify Error #",                              GetLastError() );                        return(-1);                  }                }                              }      }      return(0);    }//+------------------------------------------------------------------+//| 如果执行达到此点,                                                   |//| 说明没有挂单和开仓。                                                |//+------------------------------------------------------------------+//---- 放置 BuyStop 和 SellStop:    double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel;    _OpenPriceLevel = NormalizeDouble( Ask + Luft*Point, Digits);   if ( StopLoss > 0 )      _StopLossLevel = NormalizeDouble( _OpenPriceLevel -                        StopLoss*Point, Digits );    else      _StopLossLevel = 0.0;   if ( TakeProfit > 0 )      _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel +                        TakeProfit*Point, Digits );    else      _TakeProfitLevel = 0.0;   if(OrderSend ( Symbol(), OP_BUYSTOP, Lot, _OpenPriceLevel,      5, _StopLossLevel, _TakeProfitLevel, "", _MagicNumber ) < 0)    {      Alert( "OrderSend Error #", GetLastError() );      return(-1);    }      _OpenPriceLevel = NormalizeDouble( Bid - Luft*Point, Digits);   if ( StopLoss > 0 )      _StopLossLevel = NormalizeDouble( _OpenPriceLevel +                        StopLoss*Point, Digits );    else      _StopLossLevel = 0.0;   if ( TakeProfit > 0 )      _TakeProfitLevel = NormalizeDouble( _OpenPriceLevel -                        TakeProfit*Point, Digits );    else      _TakeProfitLevel = 0.0;   if(OrderSend ( Symbol(), OP_SELLSTOP, Lot, _OpenPriceLevel,       5, _StopLossLevel, _TakeProfitLevel, "",      _MagicNumber ) < 0 )    {      Alert( "OrderSend 错误 #", GetLastError() );      return(-1);    }   return(0);}
最初的和修改后的程序之间的不同是非常明显的 — 控制建仓的代码块变得更简单易懂。

现在轮到最复杂的智能交易程序了,它允许在同一时间无限制的新建多个仓位。
4. 控制所有仓位

现在需要有足够的变量来存储定单的信息,为此我们可以创建一些数组来实现这个目的。鉴于此,这个程序的功能将几乎和前面一样:
[*]开始时所有的数组归零;[*]在所有的定单里搜索,找到符合需要的信号和MagicNumber值后,将这些信息存储在数组中;[*]为了使可用性更强,必须添加一个全局变量来记录智能交易程序的定单个数 — 这在访问数组时会很有用。让我们立即开始编写该函数:

// 智能交易的全部定单总量变量将会存储:int _ExpertOrdersTotal = 0; // 定单特性的数组将会被存储:int _OrderTicket[], _OrderType[];double _OrderLots[], _OrderOpenPrice[], _OrderStopLoss[], _OrderTakeProfit[];double _OrderProfit[], _OrderSwap[], _OrderCommission[];datetime _OrderOpenTime[], _OrderExpiration[];string _OrderComment[]; void AllOrdersInit( int magic ){    int _GetLastError = 0, _OrdersTotal = OrdersTotal();   // 按照当前仓位总数改变数组的大小 // (if _OrdersTotal = 0, 改变数组总数为 1)    int temp_value = MathMax( _OrdersTotal, 1 );    ArrayResize( _OrderTicket,   temp_value );    ArrayResize( _OrderType,       temp_value );    ArrayResize( _OrderLots,       temp_value );    ArrayResize( _OrderOpenPrice,temp_value );    ArrayResize( _OrderStopLoss,   temp_value );    ArrayResize( _OrderTakeProfit, temp_value );    ArrayResize( _OrderOpenTime,   temp_value );    ArrayResize( _OrderProfit,   temp_value );    ArrayResize( _OrderSwap,       temp_value );    ArrayResize( _OrderCommission, temp_value );    ArrayResize( _OrderComment,    temp_value );    ArrayResize( _OrderExpiration, temp_value );   // zeroize the arrays    ArrayInitialize( _OrderTicket,   0 );    ArrayInitialize( _OrderType,       0 );    ArrayInitialize( _OrderLots,       0 );    ArrayInitialize( _OrderOpenPrice,0 );    ArrayInitialize( _OrderStopLoss,   0 );    ArrayInitialize( _OrderTakeProfit, 0 );    ArrayInitialize( _OrderOpenTime,   0 );    ArrayInitialize( _OrderProfit,   0 );    ArrayInitialize( _OrderSwap,       0 );    ArrayInitialize( _OrderCommission, 0 );    ArrayInitialize( _OrderExpiration, 0 );   _ExpertOrdersTotal = 0;    for ( int z = _OrdersTotal - 1; z >= 0; z -- )    {      if ( !OrderSelect( z, SELECT_BY_POS ) )      {          _GetLastError = GetLastError();          Print("OrderSelect(", z, ",SELECT_BY_POS) -错误 #",               _GetLastError );          continue;      }      if ( OrderMagicNumber() == magic && OrderSymbol() ==            Symbol() )      {            // 填数组            _OrderTicket = OrderTicket();            _OrderType = OrderType();            _OrderLots =             NormalizeDouble( OrderLots(), 1 );            _OrderOpenPrice =             NormalizeDouble( OrderOpenPrice(), Digits );            _OrderStopLoss =             NormalizeDouble( OrderStopLoss(), Digits );            _OrderTakeProfit =             NormalizeDouble( OrderTakeProfit(), Digits );            _OrderOpenTime = OrderOpenTime();            _OrderProfit =             NormalizeDouble( OrderProfit(), 2 );            _OrderSwap =             NormalizeDouble( OrderSwap(), 2 );            _OrderCommission =             NormalizeDouble( OrderCommission(), 2 );            _OrderComment = OrderComment();            _OrderExpiration =             OrderExpiration();            _ExpertOrdersTotal++;      }    }   // 按照智能交易所属仓位的总量改变数组的大小    // (if _ExpertOrdersTotal = 0, 改变数组大小为 1)    temp_value = MathMax( _ExpertOrdersTotal, 1 );    ArrayResize( _OrderTicket,   temp_value );    ArrayResize( _OrderType,       temp_value );    ArrayResize( _OrderLots,       temp_value );    ArrayResize( _OrderOpenPrice,temp_value );    ArrayResize( _OrderStopLoss,   temp_value );    ArrayResize( _OrderTakeProfit, temp_value );    ArrayResize( _OrderOpenTime,   temp_value );    ArrayResize( _OrderProfit,   temp_value );    ArrayResize( _OrderSwap,       temp_value );    ArrayResize( _OrderCommission, temp_value );    ArrayResize( _OrderComment,    temp_value );    ArrayResize( _OrderExpiration, temp_value );}
为了了解函数运行的详情,让我们来写一个简单的智能交易程序,它将显示该程序新建所有仓位的信息。 代码相当简单:

extern int _MagicNumber    = 0; #include AllOrdersControl.mq4> int start(){    AllOrdersInit( _MagicNumber );         if ( _ExpertOrdersTotal > 0 )    {      string OrdersList = StringConcatenate(Symbol(),                  ", MagicNumber ", _MagicNumber, ":\n");      for ( int n = 0; n _ExpertOrdersTotal; n ++ )      {            OrdersList = StringConcatenate( OrdersList,                           "Order # ", _OrderTicket,               ", profit/loss: ",               DoubleToStr( _OrderProfit, 2 ),               "
", AccountCurrency(), "\n" );                  }      Comment( OrdersList );    }   return(0);}
如果 _MagicNumber 设为 0, 智能交易程序将显示手动建仓的列表:

http://articles.mql4.com/c/articles/2006/05/allorderstest.gif
5. 总结

最后,我想来比较一下使用函数与否在搜索定单时的速度。为此,我们用相同的版本来连续测试 "Every tick" 模式10次(用_MagicNumber最优化),用 MetaTrader 软件来计算时间 — 时间时自己计算的。
结果如下:

智能交易
10 测试的时间 (mm:ss)CrossMACD_beta
(不包含函数)07:42CrossMACD11:37DoublePending_beta
(不包含函数) 08:18DoublePending09:42正如你的表格里看到的,使用函数的智能交易程序稍稍慢了一点,这作为使源代码简单易懂的代价,应该还算合理。

无论如何,每个人都有是否使用函数的自由。

MetaQuotes Software Corp. 翻译自俄语
原文: http://articles.mql4.com/ru/126




附件:
http://www.mql4.com/i/ico/mq4.gif AllOrdersControl.mq4 (4.1 Kb)
http://www.mql4.com/i/ico/mq4.gif CrossMACD.mq4 (3.0 Kb)
http://www.mql4.com/i/ico/mq4.gif CrossMACD_beta.mq4 (3.6 Kb)
http://www.mql4.com/i/ico/mq4.gif DoublePending.mq4 (4.8 Kb)
http://www.mql4.com/i/ico/mq4.gif DoublePending_beta.mq4 (6.7 Kb)
http://www.mql4.com/i/ico/mq4.gif OneOrderControl.mq4 (2.2 Kb)
http://www.mql4.com/i/ico/mq4.gif OneTypeOrdersControl.mq4 (6.5 Kb)
创建: 2006.12.06创建人: Andrey Khatimlianskyi

hefeiddd 发表于 2008-5-25 07:41

代码基地

最后添加 专家顾问 指示器 脚本 参考图书


Triggerlines Shift Modified [ en | ru ] (创建人: Scriptor)
指标 Triggerlines Shift Modified。00.019http://www.mql4.com/i/6.gifOtcfx_b-clock modified V3.2 [ ru ] (创建人: Scriptor)
指标 Otcfx_b-clock modified V3.2。修改指标的另外一种样式。00.012http://www.mql4.com/i/6.gifBZ_TL_SkylineM [ ru ] (创建人: Scriptor)
作者认为,用户可以使用该指标作为与其他所有指标的外部连接。00.018http://www.mql4.com/i/3.gifTRAYLER+ [ en | ru ] (创建人: xrust)
建议智能交易使用追踪,在创建过程中添加 "图表定单管理"00.026http://www.mql4.com/i/3.gifМТС "MoneyRain" [ en | ru ] (创建人: Reshetov)
在每笔盈利交易以后(如果在它之前有亏损交易),智能交易增加交易份额。00.042http://www.mql4.com/i/3.gifBHS system [ en | ru ] (创建人: fortrader.ru)
"圆形"数字上的系统00.019http://www.mql4.com/i/3.gif短期趋势 [ en | ru ] (创建人: fortrader.ru)
使用短期趋势的交易策略 00.0224http://www.mql4.com/i/9.gifFlatter_V1 [ en | ru ] (创建人: rosych)
脚本放置了停止定单。放置的定单可以使用指定的自定义变量 High(变量 Hi) 和Low(变量Lo)。00.022http://www.mql4.com/i/6.gifFast_oscilator_2 [ en | ru ] (创建人: xrust)
快速震荡同样适用于倒卖。00.028http://www.mql4.com/i/6.gifSpecification [ en | ru ] (创建人: Rosh)
图表对象 OBJ_LABEL使用表格显示信息的范例00.021


网页: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 > >>

hefeiddd 发表于 2008-5-25 07:43

您看到这样的图像了吗? (http://www.mql4.com/i/treadpages.gif 1 2 3 )272007.03.29Roshhttp://www.mql4.com/i/sactive.gif文章 "MetaTrader 4 客户端内的智能交易测试: 内部模式" 02008.05.01Roshhttp://www.mql4.com/i/sactive.gif文章:在 MQL4.Community上轻松简单地公布影音图像 02008.04.23Roshhttp://www.mql4.com/i/sactive.gif文章:MetaTrader 4 中比较基因演算方法和简单搜索 02008.04.18Roshhttp://www.mql4.com/i/sactive.gif文章:基因演算规则:数学运算 02008.04.08Roshhttp://www.mql4.com/i/sactive.gif文章:Strategy Tester:交易策略测试中模式化的方式 02008.04.03Roshhttp://www.mql4.com/i/active.gif请问!一单成交立即删除所有挂单要怎么实现呢? 02008.05.25zxczxchttp://www.mql4.com/i/active.gif收获 02008.05.24topeahttp://www.mql4.com/i/active.gif請問有無人可以代寫 mql4程式? 02008.05.23andersontaihttp://www.mql4.com/i/active.gif为什么这个简单的指标不能显示? 12008.05.21ordedhttp://www.mql4.com/i/active.gif请问在电脑上的指标能直接拷贝到windows mobile系统PDA的MT上吗? 12008.05.22breanchhttp://www.mql4.com/i/active.gif求助Rosh 32008.05.21smmhttp://www.mql4.com/i/active.gifHow to protect copyright of MT4 indicators? 12008.04.04song_songhttp://www.mql4.com/i/active.gif请问报警延迟Sleep怎么写? 12008.05.21xzpchihttp://www.mql4.com/i/active.gif请求热心人帮助我 12008.05.21ken_wanghttp://www.mql4.com/i/active.gif求助,MACD(12,26,9)过零轴进场如何实现? 02008.05.20cxwsxl422http://www.mql4.com/i/active.gif求助!EA中如何调用该指标? 22008.05.10tianma_2005http://www.mql4.com/i/active.gif请教各位朋友,如何把图中的报价数字变大啊? 12007.10.17papauhttp://www.mql4.com/i/active.gif请教热心人,这个指标哪里出错了? 62008.05.14mkdaoyihttp://www.mql4.com/i/active.gifMQL4 太难理解了。郁闷死了,运行效率又极底 12008.05.18aaronhttp://www.mql4.com/i/active.gif在iStochastic里的MODE参数的MODE_MAIN与MODE_SIGNAL分别是什么意思??? 22008.05.16shenxinonhttp://www.mql4.com/i/active.gif新手求教:如何将不同指标整合到一个指标窗口? 02008.05.16wi1999http://www.mql4.com/i/active.giftrouble me for very long term 02008.05.16aaronhttp://www.mql4.com/i/active.gif申请版主 12008.05.15startexcelhttp://www.mql4.com/i/active.gif关于MQL4 调用 VC6++ DLL的问题 32008.05.12aaronhttp://www.mql4.com/i/active.gifBANK OF CHINA 6013820400000448024 (http://www.mql4.com/i/treadpages.gif 1 2 3 4 5 )492008.05.09160960http://www.mql4.com/i/active.gif我在美国forex.com有外汇真实账户,如何把下单功能集合到MetaTrader软件中实现自动下单? 72008.05.10alexcaicnhttp://www.mql4.com/i/active.gifMetaEditor 太他妈的烂了,调试真的麻烦死了,我都快被搞死了,这种问题都出现。 42008.05.11aaronhttp://www.mql4.com/i/active.gif如何更好学习MQL4,有中文书那里下载? 12008.05.10puti1http://www.mql4.com/i/active.gif10、20日均线交叉自动交易系统 82008.03.26fruif

网页: 1 2 3 4 5 6 7 8 9 10 11 12 13 14




免费下载 MetaTrader 4 (3Mb) 开设交易账户

hefeiddd 发表于 2008-5-25 07:45

规则http://championship.mql4.com/i/0.gif
参与者http://championship.mql4.com/i/0.gif
赞助http://championship.mql4.com/i/0.gif
评委http://championship.mql4.com/i/0.gif
新闻http://championship.mql4.com/i/0.gif
评论

2007自动交易锦标赛MetaQuotes Software Corp., ODL Securities, Alpari (UK) Ltd., FXDD 和 TRADERS’ journal携手开启了第二年度的2007自动交易锦标赛。 锦标赛将在未来的三个月中选举出智能交易创建者的冠军、亚军、季军。 评估标准为绝对赢利。 获胜者将获得2007自动交易锦标赛提供的总数为80 000美元的奖金!
               
锦标赛的主要目的在于推广智能交易 以 MetaQuotes Language 4 (MQL4)命名的程序语言 。 数以百计的自动交易系统将在这期间公开竞争。大家可以看到在没有人类执行的智能交易中同样可以获得赢利。



2007自动交易锦标赛的获胜者2007自动交易锦标赛已经过去。大赛的获胜者们已经得到了他们的奖杯和奖金。
第一名被来自乌克兰的 Olexandr Topchylo获得。他的智能交易获得了 130 000 美元,远远领先其它参赛者 。 Olexandr获得由锦标赛主要赞助商ODL Securities Limited 提供的 40 000 美元的奖金。
http://championship.mql4.com/c/news/2008/01/better_1.jpg 第二年度的自动交易锦标赛已经结束。对锦标赛的主办者和赞助商在世界范围内构造的交易竞赛表示感谢。交易创建者们在最具竞争力的环境下获得了不可估量的宝贵经验。这些经验将帮助他们在真实市场交易起到帮助作用。我们看到了很多不同类型的智能交易。 在第一名的位置上不断地更换强进的智能交易转手倒卖者.去年的竞赛中不仅仅参赛人数少,同样交易系统的设计上也比较今年单一。创建者在大赛中获取了经验,大赛中很多智能交易拥有较高的水平。
我想,与上个年度锦标赛比较, ATC-2007更加全面地展示了自动交易的前景。如果说有谁对自动交易表示怀疑,通过这次的竞赛这种怀疑已经解除。 非常感谢 MetaQuotes Software Corp公司。感谢提供了一个亲近现代技能的机会。很高兴他们没有满于现在的成果停止研发的脚步。现在已经开始研发新版本的交易平台。也许,下一次的锦标赛可以使用MQL5呢?

第二名被来自美国的 William Boatright获得。他的智能交易在大赛中赢利55 000美元。 William 获得由金牌赞助商Alpari (UK) Limited提供的25 000 美元。
http://championship.mql4.com/c/news/2008/01/boatright.jpg 首先,我要对第二年度自动交易锦标赛的主办者 (MetaQuotes Software Co)和大赛的赞助赞助商 ( ODL Securities Limited, Alpari (UK) Limited, FXDD 和TRADERS') 表示感谢。大赛的成功举办为新老创建者们构造了一个世界范围的巨大平台,使创建者可以在世界范围内对自己的交易策略进行测试。我相信,大多数参赛者和我一样,像呵护自己孩子一样对待智能交易。我们相信对智能交易的引导,会使它们在市场中尽量避免错误出现。最后,可以说它们让我们这些父母感到骄傲。我是幸运的,我的孩子(智能交易)做的不错.
我想说的是我要感谢所有参赛的创建者们。感谢你们带着梦想和勇气,带着自己创建的智能交易和交易策略参与到2007自动交易锦标赛中来。在今年的大赛中许多参赛者得到了近 2.5% 的投资回报 (R.O.I.)。即使是 2.5% R.O.I.对于去年也增长了 10% 。对于股票,基金,个人退休账户(IRA, 401k).这是一个很好的投资回报。我发现一点简单的逻辑可以成功使用于交易策略。不要害怕在测试中试用新想法,这是我们必须要学习的。需要提醒的是在外汇交易市场需要“汲取过去,展望未来!

第三名被来自乌克兰的参赛者 Vasiliy Lavrinenko获得。 Vasiliy的智能交易在大赛中赢利近 40 000 美元,Vasiliy获得由银牌赞助商FXDD提供的15 000 美元。
http://championship.mql4.com/c/news/2008/01/lavrinenko.jpg 祝贺所有参赛者和主办方大赛圆满结束!特别要感谢锦标赛主办者出色的工作! 市场把所有参赛者放置到了一个透明的状态。老实说,我对大赛并没有准备:我在大赛开始的前2个星期才听说。我的智能交易是为了交易创建的,不是特意为了锦标赛,所以很紧急的根据锦标赛规则进行了修改。我根本没有想过会获得第三名。不过,在锦标赛结束之前一连串的事件对我的智能交易起到了帮助作用。
我相信我们将会纠正错误,使用新的策略和系统设备在下一年的竞赛中崭露头角!

MetaQuotes Software Corp.再次对锦标赛的赞助商– ODL Securities Limited, Alpari (UK) Ltd., FXDD, 和媒体赞助商, TRADERS’ 杂志表示感谢。我们对2007自动交易锦标赛的获胜者表示真诚地祝贺!我们希望创建者能够取得更多的成功,并且学习MQL4。

创建日期: 2008.01.25创建人: MetaQuotes Software Corp.

[ 本帖最后由 hefeiddd 于 2008-5-25 07:48 编辑 ]

hefeiddd 发表于 2008-5-25 07:50

2007自动交易锦标赛结束了!令世界关注的自动交易锦标赛,12期有趣的赛事- 2007自动交易锦标赛已经结束了。所有的智能交易都已经停止运作。是时候公布获胜者和奖金的时间了。
1http://championship.mql4.com/i/0.gifBetter
500008
Kub (EURUSD 1 minute)
130 475 USD
http://championship.mql4.com/i/0.gif2007自动交易锦标赛的第一名被来自乌克兰的参赛者Olexandr Topchylo 获得。Olexandr曾经参加过2006年度的锦标赛,但并没有取得成功。他从上次的竞赛中学习了很多东西之后, Olexandr 在今年赢得了比赛。他在五期的交易中一直稳稳占据前十强的位置。
Olexandr的智能交易是以神经网络为基础的。他的交易系统相当复杂,是由三个独立的子系统组成。这些能够帮助EA 掌握方向,赢得了127 000美元,以次获得了第一名。其智能交易的每笔交易的平均赢利为303 美元。这个EA的赢利原因值为 2.24。 Olexandr的智能交易证明不是只有风险 EA能够获得大的赢利。这个智能交易的效率为52%,而风险水平却仅仅将近15%。 Olexandr 成为2007自动交易锦标赛的第一名并且获得来自ODL Securities Limited 支持赞助的 40 000 美元的奖金。祝贺 Olexandr!



2
http://championship.mql4.com/i/0.gifwackena
500197
Bogie-ATC2007-1 (EURUSD daily)
55 042 USD
http://championship.mql4.com/i/0.gif第二名 的位置在上几期的比赛中竞争非常激烈。在锦标赛接近尾声时刻,这个位置被来自美国的 William Boatright以52 000美元的成绩获取。他所在自己智能交易中使用的时间周期使它很稳定。
William的智能交易是以分析大量历史数据为基础来帮助EA 决定在最佳时期开仓的。创建者自己承认他的智能交易属于风险的EA。尽管,其智能交易的风险水平要比olexandr的 ea高些。这个智能交易的赢利因素值为2.54, 效率 – 20%。这个交易系统每笔交易的平均赢利为299。由此, William 获得了2007自动交易锦标赛的第二名并且获得来自Alpari (UK) Limited 支持赞助的 25 000美元。祝贺 William!



3
http://championship.mql4.com/i/0.gifPegasmaster
500271
Pegas (GBPUSD 15 minutes)
39 945 USD
http://championship.mql4.com/i/0.gif第三名的位置被来自乌克兰的参赛者 Vasiliy Lavrinenko (PegasMaster)获得。他的智能交易-Pegas以缓慢稳定的步伐仅在最后一个星期进入了前十强的列表。不过这个智能交易的步伐相当缓慢,它的赢利远远低于前几位获胜者。不过在锦标赛的最后一天,智能交易将近获得10 000美元的赢利,以此差额获得第三名的位置。
这位参赛者的智能交易有小仓位账户和长时间持仓的特点。智能交易曾在一笔交易中持仓130 小时。他的心思没有白费。 智能交易的预期赢利目前为1 100 美元。这个值在三位参赛者中是最高的。另外,接近 80%的交易赢利。其赢利因素值稍稍高于前两位获胜者为3.03。智能交易的功效很不错为 21%。 Vasiliy获得2007自动交易锦标赛第三名并且获得来自FXDD 支持赞助的15 000美元。祝贺 Vasiliy!



2007自动交易锦标赛已经结束了。我们对所有的获胜者,和表示感谢。





规则 自动交易锦标赛 2007
I. 总规则

[*]锦标赛主办者 MetaQuotes Software Corp.[*]锦标赛赞助商:[*]主要赞助商 - ODL Securities Limited[*]金牌赞助商 - Alpari (UK) Ltd.[*]银牌赞助商 - FXDD[*]传媒赞助商 - TRADERS'[*]锦标赛时间自2007年10月1日至2007年12月21日结束.[*]登记时间开始于2007年7月1日截止至2007年9月21日.[*]奖金80 000美金分配如下:[*]冠军- 40 000美金[*]亚军 - 25 000美金[*]季军 - 15 000美金[*]参加本次锦标赛的所有自动交易系统在比赛期间均在组织者提供的服务器环境下不间断的运行。[*]所有的参加者参赛使用货币均为虚拟货币。[*]锦标赛的参与是自愿的。II. 参赛条件

[*]锦标赛参赛者必须年龄在18或以上, 不限职业,国籍和性别。[*]主办者,赞助商的职员,以及其家属和亲友均不得参加锦标赛。[*]只有登记完毕的参加者才能参加锦标赛。[*]参赛者必须在登记时提供真实资料。[*]参赛者只有一次登记参赛的机会。[*]重复登记以及提供虚假的参赛资料的参赛者将被取消参赛资格。[*]参赛者同意不向主办者者或赞助商索取包括金钱在内任何方面的赔偿要求。[*]主办者保留拒绝参赛者登记的权利,以及对参赛者丧失参赛资格提供证明权利。[*]对任何登记参赛的参赛者,都将视同明确所有比赛规则且对比赛规则没有任何异议。III. 可选的自动交易程序

[*]程序仅接受*.EX4 文件及原始码*.MQ4文件和 DLLs文件被禁止。[*]下列各项允许被使用:[*]一个智能交易 ( 放入 /experts目录下)。[*]一个数据文件 ( 放入 /expert/files目录下) 除可运行的以外的任何的格式。[*]最多5个自定义的技术指标( 放入/experts/indicators目录下) 对自定义技术指标没有任何限制。[*]最多5 个类 (放入/experts/libraries目录下)。[*]每个自动交易程序只能在一个终端上开设的一个账户,只可以选择一种图表使用。[*]所有参赛自动交易系统只能在组织者提供的环境下运行,没有外部控制。[*]在参赛者被锦标赛接受之前,每个自动交易程序均需主办者测试以证实符合参赛规则。[*]可以引用锦标赛之外使用的自动交易系统,但必须满足以下条件:[*]在2007年间测试运行正常(历史测试并不是必须的,简单的描述即可)[*]在帐户号码从 500 000 到 510 000运行正常[*]使用demo.metaquotes.net:443的伺候器上开设的模拟账户可以正常工作[*]正确的考虑 货币的设置不要有硬性规定的参数 (限制在手数,点差, 市场报价的最小误差)[*]绝对不包含致命的漏洞(比如死循环或者挂起等等) 或明确有害的行动[*]合理的使用处理器和个人计算机内存[*]如果在比赛期间使用的自动交易程序与先前送至主办者测试的自动交易程序不同,参赛者将被取消参赛资格。IV. 交易条款

[*]在比赛期间将有命名为" demochampionship" 的特殊帐户群在示范服务器 demo.metaquotes.net上可选择。 该账户群的帐户只有主办者可以打开。帐号从 500 000 到 510 000 将用于参赛账户。[*]起始 " 虚拟的保证金 " 被定义为 US$ 10000, 杠杆为1:100。[*]锦标赛已经选定12货币兑.[*]最小的交易单位为0.1标准手, 允许最大的交易为 5个标准手每个定单一步为0.1标准手。[*]在一个参赛帐户可以同时存在3单5个标准手的开仓单和挂单。[*]Stop Out=50%[*]比赛的交易环境和真实帐户交易环境相近:[*]交易处理时间 2 到 7 秒[*]有序报价[*]在新闻公布时市场报价的误差可能扩大化[*]在新闻公布时可能会出现报价缺口[*]以非市价成交价成交的仓单将会被取消[*]更多的详情请参照附录 1.V. 比赛结果的公布

[*]在冠军赛期间, 下列各项将会自动实时公布:[*]所有的参赛者的状态[*]所有参赛终端的日志 (终端的日志和自动交易系统的日志)[*]排名和比较表格每 5 分钟被更新。[*]参赛者的帐户和只读密码为公开。登陆后仅有观察权限。VI. 自动交易程序源代码的安全性及保密性

[*]未经参赛者授权公布其自动交易系统,主办者保证在锦标赛完毕后将会立刻删除参赛者提交的所有自动交易程序的相关文件(包括自定义的技术指标和类)。[*]主办者保证在比赛期间只有MetaQuotes 软件公司的被授权职员能登陆参赛者的程序。[*]如果三方(评委会,主办者,参赛者)认为某一参赛者违反参赛条款,该参赛者必须提交其参赛的自动交易程序以便审查。如果参赛者拒绝提交,则该参赛者将被取消参赛资格。VII. 获奖者的评定

[*]在锦标赛完成 (2007年12月21日23:59交易时间) 之后,所有的仓单将会被强行平仓。[*]在锦标赛结束后,保证金数值最大的三位参赛者将赢得锦标赛的3个大奖。[*]如果 2 或2个以上的参赛者的保证金相同,则由审查委员会作出最后的获奖人选。[*]如果没有一个参赛者帐户获利,该锦标赛将没有优胜者。[*]获胜者必须同意公开姓名.[*]获胜者必须同意参加主办者和赞助者引导的促销活动广告, 包括访问, 照片报告, 以及大众传媒的报道。VIII. 奖金的支付

[*]获胜者必须在公告公布7个工作日内将护照复印件(护照的首页及其落地签页)传真至 (+7 843 570-00-37转 105 或者+357 25 580191)以便确认他们的身份。如果获胜者未按照以上要求提供其证件,将视为自动放弃奖金[*]获胜者必须在宣布成为获胜者后7个工作日内提供账户银行的详细信息。[*]如果组织者在 7 天之内不能够连络到获胜者 (电话方式),获胜者被评委判定丧失资格,而且获胜者名单将会被校正。[*]奖金将会以银行转帐形式打入获奖者的帐户,获奖者在7个工作日内收到奖金。

hefeiddd 发表于 2008-5-25 07:54

登陆姓名注解国家赢利原因差额赢利净值1500008Better673Ukraine2.18130 475.450.00130 475.45http://championship.mql4.com/i/terminal/botus.gif2500197wackena102United States2.4055 042.100.0055 042.10http://championship.mql4.com/i/terminal/botus.gif3500271Pegasmaster40Ukraine3.0339 945.810.0039 945.81http://championship.mql4.com/i/terminal/botus.gif4500123draz26Croatia1.3739 547.760.0039 547.76http://championship.mql4.com/i/terminal/botus.gif5500162zyx4041Russia1.9636 858.400.0036 858.40http://championship.mql4.com/i/terminal/botus.gif6500087YuraZ45Russia2.1235 222.970.0035 222.97http://championship.mql4.com/i/terminal/botus.gif7500097Saloght39Russia1.7734 888.700.0034 888.70http://championship.mql4.com/i/terminal/botus.gif8500494Newman222Canada2.0431 952.460.0031 952.46http://championship.mql4.com/i/terminal/botus.gif9500030TeamSky18Japan5.1629 924.870.0029 924.87http://championship.mql4.com/i/terminal/botus.gif10500445Greezly15Ukraine2.9626 932.050.0026 932.05http://championship.mql4.com/i/terminal/botus.gif11500022maxfade22Ukraine1.2125 933.580.0025 933.58http://championship.mql4.com/i/terminal/botus.gif12500274rfiche18Brazil1.7025 497.510.0025 497.51http://championship.mql4.com/i/terminal/botus.gif13500432winwin2007714Germany2.2325 443.600.0025 443.60http://championship.mql4.com/i/terminal/botus.gif14500179Richi_k26Bulgaria2.9624 874.120.0024 874.12http://championship.mql4.com/i/terminal/botus.gif15500062dogada2Ukraine4.5524 584.480.0024 584.48http://championship.mql4.com/i/terminal/botus.gifhttp://championship.mql4.com/i/0.gif网页:
1
2
3
4
5
6
7
8
9
10
> >>

hefeiddd 发表于 2008-5-25 08:01

新闻 自动交易锦标赛 2007http://championship.mql4.com/c/news/icons/343.gif 2007自动交易锦标赛的获胜者
锦标赛已经结束。获胜者得到了应得的惊喜和奖杯,并与我们一起分享了自己的想法。


公布者: MetaQuotes Software Corp. 2008.01.25 10:05 http://championship.mql4.com/c/news/icons/339.gif 2007自动交易锦标赛结束了!
令世界关注的自动交易锦标赛,12期有趣的赛事- 2007自动交易锦标赛已经结束了。所有的智能交易都已经停止运作。是时候公布获胜者和奖金的时间了。


公布者: MetaQuotes Software Corp. 2007.12.25 15:35 http://championship.mql4.com/c/news/icons/340.gif 2007年12月19 日评委会议报告
我们组办2007自动交易锦标赛的目的在于使所有参赛者在平等的条件下进行公平地竞争。带着这种目的我们曾经在赛前对所有智能交易进行了检查,防止参赛者多次注册。由于一些参赛者想要增加赢得几率。


公布者: MetaQuotes Software Corp. 2007.12.25 15:27 http://championship.mql4.com/c/news/icons/338.gif 组织者笔记
2007自动交易锦标赛已经圆满结束。


公布者: MetaQuotes Software Corp. 2007.12.24 12:16 http://championship.mql4.com/c/news/icons/331.gif 统计报告#3
在当前的统计报告中我们对12月10日前十强的智能交易进行了分析。使用了与2006自动交易锦标赛统计报告3 同样的方法进行了分析。


1 评论公布者: MetaQuotes Software Corp. 2007.12.19 16:13
http://championship.mql4.com/i/0.gif
网页:
1
2
3
4
5
6
7
8
9

hefeiddd 发表于 2008-5-25 08:03

2007.03.30 16:19I often visit different forums. Several times a day, to be more exact.
Sometimes, I see very interesting screenshots of the terminal. Those can be indicators, EAs, objects, etc.
I think it would be a pity if all that treasure were lost, traders should see it!
So I propose to upload to this thread screenshots you liked and would like to show to others. I, myself, place some screenshots here: two of them are mine, three are saved previously.

WEB
http://forum.mql4.com/c/forum/2007/03/333.gif

hefeiddd 发表于 2008-5-25 08:04

Barrage grid

http://forum.mql4.com/c/forum/2007/03/eur_usd_06_04_02_w_northfinans.gif



Hand Made

http://forum.mql4.com/c/forum/2007/03/first.png



Murrey +Zigzag
http://forum.mql4.com/c/forum/2007/03/post-1729-1169848842.gif


Channells
http://forum.mql4.com/c/forum/2007/03/uo.gif

hefeiddd 发表于 2008-5-25 08:37

2007.04.03 09:28http://forum.mql4.com/c/forum/2007/04/as_1.jpg

hefeiddd 发表于 2008-5-25 08:41

2007.04.15 02:00http://forum.mql4.com/c/codebase/2007/04/trendstat_1.gif

http://forum.mql4.com/c/codebase/2007/04/trendstat_history_1.gif

http://forum.mql4.com/c/codebase/2007/04/_dashboard_1.gif

hefeiddd 发表于 2008-5-25 08:43

2007.04.18 14:39We have developed a trading program that analyzes the FOREX market using algorithmic formula. It clearly indicates entry, take profit and stop points to the user. trhough a custom indicator used in combination with MetaTrader4.





http://forum.mql4.com/c/codebase/2007/04/pip2profit_1.gif

hefeiddd 发表于 2008-5-25 08:44

2007.04.18 18:08http://forum.mql4.com/c/codebase/2007/04/feed.gif
页: 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 [1104] 1105 1106 1107 1108 1109 1110 1111 1112 1113
查看完整版本: 一个笨蛋的股指交易记录-------地狱级炒手