English Русский Español Deutsch 日本語 Português
简单的订单管理

简单的订单管理

MetaTrader 4交易 | 6 十二月 2006, 16:16
14 904 2
Andrey Khatimlianskii
Andrey Khatimlianskii

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;

        }

    }

    //---- もし両方の指値注文がある場合、終了します 

    //---- そのうちの1つが作動するまで待つ必要があります

    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 ) - Error #",

                _GetLastError );

          continue;

        }

// もしポジションが現在のツールで開いていない場合、スキップします

        if ( OrderSymbol() != Symbol() ) continue;

// もしMagicNumberが_MagicNumberと等しくない場合、このポジションをスキップします

        if ( OrderMagicNumber() != _MagicNumber ) continue;

// ポジションタイプによって変数の値を変えます:

        switch ( OrderType() )

        {

            //---- もし開いている買いポジションがある場合、

            case OP_BUY:

            {

                //---- もしセルストップがまだ削除されていない場合、これを削除します:

                if ( SellStopOrder > 0 )

                {

                    if ( !OrderDelete( SellStopOrder ) )

                    {

                        Alert( "OrderDelete Error #", GetLastError() );

                        return(-1);

                    }

                }

                //---- ストップロスを移動する必要があるかをチェックしましょう:

                //---- もしトレーリングストップのサイズがあまり小さくない場合、

                if(TrailingStop > MarketInfo( Symbol(), MODE_STOPLEVEL))

                {

                  //---- もしポジションの利益はTrailingStopポイントよりも大きい場合、

                  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 Error #",

                                    GetLastError());

                              return(-1);

                            }

                        }                    

                    }

                }

                // もしオープンポジションがある場合、終了します 

                // これ以上することはありません

                return(0);

            }

            // 次のブロックは完全に 

            // 買いポジションの処理ブロックと同じです

            // そのためこれに対するコメントは付けられていません

            case OP_SELL:

            {

                if ( BuyStopOrder > 0 )

                {

                    if ( !OrderDelete( BuyStopOrder ) )

                    {

                        Alert("OrderDelete Error #",

                              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);

            }

        }

    }

//+------------------------------------------------------------------+

//| もし実行がこの場所に到達した場合、それは指値注文や|

//| 開いているポジションがないということ                                |

//+------------------------------------------------------------------+

//---- バイストップやセルストップを設定します:

    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[_ExpertOrdersTotal] = OrderTicket();
            _OrderType[_ExpertOrdersTotal] = OrderType();
            _OrderLots[_ExpertOrdersTotal] = 

            NormalizeDouble( OrderLots(), 1 );
            _OrderOpenPrice[_ExpertOrdersTotal] = 

            NormalizeDouble( OrderOpenPrice(), Digits );
            _OrderStopLoss[_ExpertOrdersTotal] = 

            NormalizeDouble( OrderStopLoss(), Digits );
            _OrderTakeProfit[_ExpertOrdersTotal] = 

            NormalizeDouble( OrderTakeProfit(), Digits );
            _OrderOpenTime[_ExpertOrdersTotal] = OrderOpenTime();
            _OrderProfit[_ExpertOrdersTotal] = 
            NormalizeDouble( OrderProfit(), 2 );
            _OrderSwap[_ExpertOrdersTotal] = 

            NormalizeDouble( OrderSwap(), 2 );
            _OrderCommission[_ExpertOrdersTotal] = 
            NormalizeDouble( OrderCommission(), 2 );
            _OrderComment[_ExpertOrdersTotal] = OrderComment();
            _OrderExpiration[_ExpertOrdersTotal] = 
            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[n], 
                ", profit/loss: ", 

                DoubleToStr( _OrderProfit[n], 2 ), 
                " ", AccountCurrency(), "\n" );            
        }

        Comment( OrdersList );
    }
 
    return(0);
}

如果 _MagicNumber 设为 0, 智能交易程序将显示手动建仓的列表:

5. 总结


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

结果如下:

智能交易

10 测试的时间 (mm:ss)

CrossMACD_beta
(不包含函数)
07:42
CrossMACD 11:37
DoublePending_beta
(不包含函数)
08:18
DoublePending 09:42

正如你的表格里看到的,使用函数的智能交易程序稍稍慢了一点,这作为使源代码简单易懂的代价,应该还算合理。


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


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

最近评论 | 前往讨论 (2)
tao zemin.
tao zemin. | 9 9月 2013 在 01:40
老大,简单的订单管理,经您一翻译,我反而还看不懂了?!
Quan Xiao
Quan Xiao | 9 5月 2018 在 14:19

老大,你翻译的时候漏了一个符号 

最后一段里:#include AllOrdersControl.mq4>

应该是:#include <AllOrdersControl.mq4>

我测试了半天用不了,还以为是我的MT4版本不支持,仔细一检查,才发现少了一个符号

智能测试报告中数字的意义 智能测试报告中数字的意义
文章全面解释怎样阅读测试报告并且精确诠释获得的结果
MetaTrader 4 客户端的秘密: MetaEditor 里的文件库 MetaTrader 4 客户端的秘密: MetaEditor 里的文件库
当我们编写程序时,代码的编辑是非常重要的。MetaEditor 作为 MQL 4 的编辑器,为我们提供了许多快捷便利的功能,大多数程序都能在已有的代码基础上完成。您是否还没有找到完全符合您期望的指标和脚本?您可以在我们的网站下载代码并加以定制。
交易中的数学: 交易仓结果的评估 交易中的数学: 交易仓结果的评估
相信很多人都听过这样一句话 "一次的成功不能保证永远成功"。我们必须对交易的结果进行评估。在这篇文章中我们将讲述简单实用的评估方法。
在一些指标中多次重新计算基础柱体 在一些指标中多次重新计算基础柱体
本文讨论当基础柱体改变时,在 MetaTrader 4 客户端里重新计算指标值的问题。它概括了如何添加指标代码的综合思路。在多次重新计算前保存一些允许重建程序代码的额外程序项。