分享

简单的订单管理

 weewas 2010-08-06

简单的订单管理 [ en | ru ]


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[_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 Software Corp. 翻译自俄语
原文: http://articles./ru/126


创建: 2006.12.06  创建人: Andrey Khatimlianskii
警告: 所有资料属MetaQuotes Software Corp版权所有. 所有资料或部分资料不得复制和转载.
交易中的数学: 交易仓结果的评估
交易中的数学: 交易仓结果的评估

相信很多人都听过这样一句话 "一次的成功不能保证永远成功"。我们必须对交易的结果进行评估。在这篇文章中我们将讲述简单实用的评估方法。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约