1. 介绍
每个智能交易程序里都有一段代码是控制建仓的。它在所有的定单中持续搜索,通过信息选择仓位,然后执行修改和关闭。这段代码看上去都差不多,而且往往具有相同的功能。这就是为何这段经常被重复的代码可以从程序中提取出来形成函数,进而使程序更易写更简洁。首先,我们按功能把任务分成三个步骤 — 这三个步骤其实是三种智能交易程序:
[*]智能交易程序在与一时间只能新建一个仓位[*]智能交易程序在与一时间可以新建每个类型的一个仓位(比如, 多头和空头的仓位)[*]智能交易程序可以同期新建多个仓位
2. 一个仓位
只新建一个仓位有很多中策略。该种控制代码块非常简单,但写出来也会耗费适当的时间和精力。
举一个简单的例子,一个来自于 MACD 线交叉点(信号线和基础线)的建仓信号,简化它的控制代码块,程序如下: 复制代码
extern int _MagicNumber = 1122;
int start()
{
//---- 记住指标值做分析报告
double MACD_1 = iMACD(Symbol(), 0, 12, 26, 9, PR洲际交易所_CLOSE,
MODE_MAIN, 1 );
double MACD_2 = iMACD(Symbol(), 0, 12, 26, 9, PR洲际交易所_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
int start(){int _GetLastError = 0;// 记住开仓的参数(假使可用)OneOrderInit( _MagicNumber );//---- 记住指标值用作分析double MACD_1 = iMACD(Symbol(), 0, 12, 26, 9, PR洲际交易所_CLOSE,MODE_MAIN, 1 );double MACD_2 = iMACD(Symbol(), 0, 12, 26, 9, PR洲际交易所_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);}