最近突然对自动化交易感兴趣,用到了一次性平仓所有订单的函数,于是从网上copy了一段代码,稍微精简了一下,就有了以下问题代码:
void ClosePosition()
{
for(int i=0; i<OrdersTotal(); i++)
{
OrderSelect(i, SELECT_BY_POS);
if(OrderType()==OP_BUY)
{
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_BID),3);
}
else if(OrderType()==OP_SELL)
{
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_ASK),3);
}
}
}
在实际调用时,发现只能平掉部分仓,只有多次调用才能完全平仓。
参考了别人程序中的代码,以及经过调试之后,找到了问题所在:
当OrderSelect函数通过SELECT_BY_POS方式获取订单时,每次执行都是从当前的持仓列表中按时间先后顺序获取订单。如果在获取订单之后持仓列表发生变动,下次获取时是从发生变动之后的新列表中获取。
所以如果按以上代码,从0号订单开始循环,获取0号订单并关闭之后,持仓列表就被更新重新排序,那么下次循环时通过OrderSelect获取到的1号订单实际对应的是未关闭0号时列表中的2号订单。
这也是为什么这段代码只能按间隔顺序关闭一半的订单。
所以解决方法就很简单了,就是在持仓列表中从尾部开始向前获取订单,这样每次关闭一个订单之后都不会影响前面的订单顺序:
void ClosePosition()
{
for(int i=OrdersTotal()-1; i>=0; i--) //从尾部开始循环
{
OrderSelect(i, SELECT_BY_POS);
if(OrderType()==OP_BUY)
{
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_BID),3);
}
else if(OrderType()==OP_SELL)
{
OrderClose(OrderTicket(),OrderLots(),MarketInfo(OrderSymbol(), MODE_ASK),3);
}
}
}
|