求解有关 PositoinsTotal() 函数的问题

 

代码如下:

#include <Trade\Trade.mqh>

CTrade    m_trade;

void OnStart() 
  { 

  double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

  m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);

  Print("开仓完毕 仓位数量",PositionsTotal());

  //Sleep(1000);
  //Print("开仓完毕 仓位数量",PositionsTotal());

  }

今天想换个平台跑下程序,然后发现代码出现各种问题,其中这个问题就是,就如上述代码,在A平台运行,会正确打印单数,在B平台运行会少一个,如果让程序休息1秒(sleep()),它就可以打印正确的

按理来说,能正常开仓,且产品是EURUSD这类常规产品,就上述代码不停运行应该就是不停打印1,2,3的顺序,可是B平台每次都会少一个,无论是手动新加额外单子,还是用其他类型的代码,我是研究了一下发觉是这个PositionTotal() 函数造成的

有一个前提是,A平台下单的速度平均都是比B平台慢一些,所以可能是导致A对的问题,但是,这个函数不是应该无论下单速度多快,都是应该返回实际数值的么?

有人知道这个是什么问题么?这个函数要正确运行是否还要增加什么前置代码么?

 
Mage He:

代码如下:

今天想换个平台跑下程序,然后发现代码出现各种问题,其中这个问题就是,就如上述代码,在A平台运行,会正确打印单数,在B平台运行会少一个,如果让程序休息1秒(sleep()),它就可以打印正确的

按理来说,能正常开仓,且产品是EURUSD这类常规产品,就上述代码不停运行应该就是不停打印1,2,3的顺序,可是B平台每次都会少一个,无论是手动新加额外单子,还是用其他类型的代码,我是研究了一下发觉是这个PositionTotal() 函数造成的

有一个前提是,A平台下单的速度平均都是比B平台慢一些,所以可能是导致A对的问题,但是,这个函数不是应该无论下单速度多快,都是应该返回实际数值的么?

有人知道这个是什么问题么?这个函数要正确运行是否还要增加什么前置代码么?

m_trade.PositionOpen(......)是bool类型,服务器不是每一个OrderSend()的请求都必须接受,服务器可以有很多种原因拒绝OrderSend()的请求,所以,为确认发送给服务器的请求是否被成功接受,务必检查 m_trade.PositionOpen(......)的结果是否为true,如果检查结果为true以后,再进行下一步的逻辑运算才靠谱,上面可以试试修改成这样,祝你好运:

if(m_trade.PositionOpen(..........)==true)

   {

         Print(.........);

   }

 
hbsbill #:

m_trade.PositionOpen(......)是bool类型,服务器不是每一个OrderSend()的请求都必须接受,服务器可以有很多种原因拒绝OrderSend()的请求,所以,为确认发送给服务器的请求是否被成功接受,务必检查 m_trade.PositionOpen(......)的结果是否为true,如果检查结果为true以后,再进行下一步的逻辑运算才靠谱,上面可以试试修改成这样,祝你好运:

if(m_trade.PositionOpen(..........)==true)

   {

         Print(.........);

   }

刚好,我正好这样写了,也是一样的结果,真的,我在反复测试的时候我用了你这个办法,而且是一抹一样的语句

#include <Trade\Trade.mqh>
CTrade    m_trade;
void OnStart() 
   { 

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0))

      {

      Print("开仓完毕 仓位数量",PositionsTotal());

      }

   //Sleep(1000);
   //Print("开仓完毕 仓位数量",PositionsTotal());
   }

他这样每次还是打印少一个,在B平台,平台名字肯定不能说了,但是我觉得是个大平台,平台方面应该是没有问题的我觉得

 
Mage He #:

刚好,我正好这样写了,也是一样的结果,真的,我在反复测试的时候我用了你这个办法,而且是一抹一样的语句

他这样每次还是打印少一个,在B平台,平台名字肯定不能说了,但是我觉得是个大平台,平台方面应该是没有问题的我觉得

那你可以查阅客户端里的这篇文章《MetaTrader5中的交易事件》,这篇文章是官网编写的,直接下载文章的示例代码,代码可以直接运行,使用全局变量来计数,先初始化,再下单,再计算,看看能不能算出来,祝你好运。https://www.mql5.com/zh/articles/232?utm_campaign=articles.list&utm_medium=special&utm_source=mt5terminal

 
hbsbill #:

那你可以查阅客户端里的这篇文章《MetaTrader5中的交易事件》,这篇文章是官网编写的,直接下载文章的示例代码,代码可以直接运行,使用全局变量来计数,先初始化,再下单,再计算,看看能不能算出来,祝你好运。https://www.mql5.com/zh/articles/232?utm_campaign=articles.list&utm_medium=special&utm_source=mt5terminal

多谢你的文章,我看到这个文章想到以前研究过的一个东西,好像虽然订单成功,但是某些信息是没有返回的,很可能我需要在 OnTradeTransaction() 事件里面去获取订单量

谢谢你!我明天把这个获取的写到那个事件里试试,预估应该就会解决了。

 

发觉,在一定高速响应的系统上,用上系统自带的事件可以更加精确的获取信息,比如

void  OnTradeTransaction( 
   const MqlTradeTransaction&    trans,        // 交易结构 
   const MqlTradeRequest&        request,      // 请求结构 
   const MqlTradeResult&         result        // 结果结构 
   );

这个函数,之前一直觉得好像没有什么用,因为不知道订单成功后也不一定返回正确的订单量,实际上的问题还是不知道

PositionsTotal()

这个函数的具体内容,如果知道了,可能就知道具体为什么不能正确返回了。

希望MT5可以将很多系统自带函数写得更加清楚明白,例如有很多函数,比如:

SymbolInfoInteger() , SymbolInfoDouble() 

这类函数,会非常的消耗计算时间,如果写在For循环里面,将会呈10倍的增加运算速度,

iHighest() iHigh() OrderCalcMargin()

这几类也是会大幅增加。

但是在不知道函数内部具体构成的时候,只能通过细微调试才能明白问题在哪,这无疑多耗费了很多的时间和精力,甚至很可能最后结论也不一定对。

所以如果可能的话,希望可以让我们多了解下MQL5语言系统自带函数的内部构造。

 
hbsbill #:

那你可以查阅客户端里的这篇文章《MetaTrader5中的交易事件》,这篇文章是官网编写的,直接下载文章的示例代码,代码可以直接运行,使用全局变量来计数,先初始化,再下单,再计算,看看能不能算出来,祝你好运。https://www.mql5.com/zh/articles/232?utm_campaign=articles.list&utm_medium=special&utm_source=mt5terminal

但是还是有个问题,只是跑出来大家可以讨论下,这个 PositionsTotal() 本身不就是应该可以直接获取当前未平订单量的嘛,也不需要填充缓存之类的就可以的,那现在程序不能正确读取,是头很疼也不知道问题在哪

现在周六也没法运行检测。

我知道的,程序得不到自己想要的结果肯定就是代码出问题,可是,这简单的三行代码……

#include <Trade\Trade.mqh>
CTrade    m_trade;
void OnStart() 
   { 

   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0))

      {

      Print("开仓完毕 仓位数量",PositionsTotal());

      }

  }
 

trade.PositionOpen是下達交易的指令 只要你參數正確訂單就會發送成功並返回true

但是不代表交易成功 所以PositionTotal()不一定會增加

你前面說用了兩個平台測試 響應或交易服務器成交效率不一樣 所以會有不一樣的呈現結果

 
Hung Wen Lin #:

trade.PositionOpen是下達交易的指令 只要你參數正確訂單就會發送成功並返回true

但是不代表交易成功 所以PositionTotal()不一定會增加

你前面說用了兩個平台測試 響應或交易服務器成交效率不一樣 所以會有不一樣的呈現結果

那请问如果想要正确的获取当前仓位总数,应该要怎么写才能做到?

 

我做了另一个测试,还是无法得到正确的结果

我起初是在ontick里面,连续开仓后,获取 持仓量 总数,获得的结果不正确

void OnTick()
   {
   if(!ck.checkTradetime(_Symbol)) return;	//确认交易时间用的,无须在意
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);	//这只是小型测试,请不要在意没有用FOR循环
   Print("开仓完毕(OnTick) 仓位数量 ",PositionsTotal());
   }

这个结果是每次都会少打一个数量,实际打印就是4 9 14 19 24

这个我已经知道OrderSend的特性,就算返回true也不是真的交易成功,返回10009结果代码也不是

我不是想测试OrderSend的,我是想获取仓位实际情况

那么我用另外一个尝试,在 OnTradeTransaction里

void OnTick()
   {
   if(!ck.checkTradetime(_Symbol)) return;
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   m_trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, 0.01, ask , 0, 0);
   }
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
   if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
      {
      Print("开仓完毕(OnTradeTransaction) 仓位数量 ",PositionsTotal());
      }
  }

用这样,打印出来也是不对,每次打印只有最后一个是对的,前面也是,比如第一次打印5组,基本都是4???5这种类型,问号代表4或者5

我也知道,这个OnTradexxxx的特性,在帮助文档里面也有写:

从程序端或通过OrderSend()/OrderSendAsync()函数手动发送的交易请求可以在交易服务器生成几个连续的事务。但不保证这些交易在程序端的优先到达。因此,开发您的交易算法时,您不必指望交易会一组接一组地到达。此外,交易可能在从服务器传递到终端过程中会丢失。

他可能丢失,也可能顺序不对,但是他怎么是从4开始打印,不是从1呢?会不会是这个原因

申请客户账户交易事务后,它们始终置于程序端交易事务队列,从这里它们一直送到OnTradeTransaction入口点以便到达程序端。

当使用OnTradeTransaction处理程序通过EA交易处理交易事务时,程序端会继续处理新来的交易事务。因此,交易账户的状态可以在OnTradeTransaction操作过程中已经改变。

那么,就算是这样,比如进入第一个事件的时候,客户端实际上已经处理完毕4单,那么打印出来4单,这可以理解。

那么是否可以这样理解,在一轮程序(所有Ontick和OnTrade都运行完毕后),在新Ontick发生的一开始,使用PositionsTotal就可以获取正确 持仓量

我带着这个疑问修改了一下代码,将打印语句放在最开始,这回打印正确了。

//---

所以我们是否可以认为,PositionTotal() 的逻辑和OnTradexxxx() 这个函数的逻辑是差不多的,都是有列队延迟的情况,因此在程序当中穿插获取持仓量,是有时候因为排队问题导致获取不到正确结果

因为无法知道  PositionTotal() 的内部代码,无法证实,只能在日后的写程序的过程中留个心眼

//---

回头看我那些可以运行的程序,刚好就是在所有操作前,使用 PositionTotal() ,没有在操作后使用它的,因此没有出问题

由此又引发了我的担心,除开  PositionTotal() 这个函数是会有排队问题 ,还有什么其他函数会有?比如简单的获取当前价的 SymbolInfoDouble() 会不会有?

不得而知。

 

也许下个Ontick也没有处理完操作的话,可能在Ontick第一个语句获取总数也不对

所以还是不知道怎么去确认这个事情:【确认订单已经交易完成】

我随后测试了一下每次Ontick 里面交易100次,打印是正确的,虽然没有反复多次测试(我目前也不知道怎么去测试),但是根据这个情况我猜测是:

每一次的Ontick交易事件处理完毕后,才会进入新的tick事件。查看了下帮助文档,中文看不懂那个翻译的意思,看了下英文发现,的确是如此。

NewTick #

In case when OnTick function for the previous quote is being processed when a new quote is received, the new quote will be ignored by an Expert Advisor, because the corresponding event will not enqueued.

All new quotes that are received while the program is running are ignored until the OnTick() is completed. 


写到这我又乱了,到头来还是没有办法在操作订单的过程中准确获取持仓量,因为我没有找到合适的办法去确认订单是否成功。


有没有人有办法可以正确获取持仓量么?

原因: