错误146 ("交易作业忙") 和如何处理
2024-03-18 10:46:02
more 
502
1.MetaTrader 4客户端中 "交易运作" 的概念
来自MetaEditor参考文档的一段话:
来自智能交易和脚本的交易,只能够提供一个并在交易作业中开启 (来自智能交易和脚本的自动交易作业)。这就是为什么如果智能交易业务作业忙,其他的智能交易或脚本在此刻不能调用函数生成错误146 (ERR_TRADE_CONTEXT_BUSY)。
换句话说,只有一个智能交易(脚本)可以准时交易。所以其他智能交易尝试开始交易将被错误 146停止。文章将会找到问题的解决方案。

2. 函数 IsTradeAllowed()
这是最简单的方法是使用名称为IsTradeAllowed()的函数找出交易作业忙。
来自 MetaEditor参考文档的一段话:
"bool IsTradeAllowed()
如果智能交易允许交易,返回TRUE 。否则,返回FALSE。
这就意味着如果函数 IsTradeAllowed()返回TRUE只有一个可以尝试交易。
在交易业务之前必须检测完成。

函数错误使用范例:
  1. int start()
  2.   {
  3.     // 检测交易作业
  4.     if(!IsTradeAllowed())
  5.       {
  6.         // 如果函数IsTradeAllowed() 返回FALSE, 通知用户
  7.         Print("交易作业忙。智能交易不能开仓!");
  8.         // 并且中止交易业务。当下一个替克进入将重新开始 
  9.         // 进入
  10.         return(-1);
  11.       }
  12.     else
  13.       {
  14.         // 如果函数IsTradeAllowed()返回TRUE,通知用户 
  15.         // 并继续运行
  16.         Print("交易作业空闲!开始运作...");
  17.       }
  18.     // 现在检测市场
  19.     ...
  20.     // 计算止损和赢利水平和标准手
  21.     ...
  22.     // 开仓
  23.     if(OrderSend(...) < 0) 
  24.         Alert("开仓错误 # ", GetLastError());
  25.     return(0);
  26.   }

复制代码
在这个范例中,在start() 函数开始时检测交易运作状态。这是个错误想法: 在我们的智能交易计算的时间内交易作业会被其他智能交易占据(需要进入市场,止损和赢利,标准手等等)。这些情况,接受开仓将失败。

函数适当应用范例:
  1. int start()
  2.   {
  3.     // 现在检测市场
  4.     ...
  5.     // 计算止损和赢利水平,标准手数
  6. ...
  7.     // 现在检测交易作业
  8.     if(!IsTradeAllowed())
  9.       {
  10.         Print("交易作业忙! 智能交易不能开仓!");
  11.         return(-1);
  12.       }
  13.     else
  14.         Print("交易作业正常! 尝试开仓...");
  15.     //如果检测正常,开仓
  16.     if(OrderSend(...) < 0) 
  17.         Alert("错误开仓 # ", GetLastError());
  18.     return(0);
  19.   }

复制代码
在开仓之前立即检测交易作业状态,并且可能在两种动作行为之间插入其他的智能交易 .
这种方法存在两点不足:
智能交易在接收到明确结果检测状态的同时,将尝试开始交易.
如果检测失败,智能交易将尝试使用下一个替克交易; 将会延误.
解决第二种不足很简单:等待交易作业空闲即可.随后,在其他智能交易结束后,智能交易将立即开始交易.

范例如下:
  1. int start()
  2.   {
  3.     // 现在检测是否进入市场
  4.     ...
  5.     // 计算赢利/止损水平和标准手数
  6.     ...
  7.     // 检测交易作业是否空闲
  8.     if(!IsTradeAllowed())
  9.       {
  10.         Print("交易作业忙!等待空闲...");
  11.         // 无限循环
  12.         while(true)
  13.           {
  14.             // 如果智能交易被用户停止,停止业务
  15.             if(IsStopped()) 
  16.               { 
  17.                 Print("智能交易被用停止!"); 
  18.                 return(-1); 
  19.               }
  20.             // 如果交易作业空闲,开始交易
  21.             if(IsTradeAllowed())
  22.               {
  23.                 Print("交易作业空闲!");
  24.                 break;
  25.               }
  26.             // 如果没有条件设置循环, "等待" 0.1秒
  27.             // 并且检测重新开始
  28.             Sleep(100);
  29.           }
  30.       }
  31.     else
  32.         Print("交易作业空闲!尝试开仓...");
  33.     // 尝试开仓
  34.     if(OrderSend(...) < 0) 
  35.         Alert("错误开仓 # ", GetLastError());
  36.     return(0);
  37.   }

复制代码
这种情况出现,我们可以指出以下错误:
函数 IsTradeAllowed()不仅仅能够显现交易作业的状态,同样可以在无限循环中以“隐藏”开启/关闭;如果从图表中手动移除,将停止运作。
如果智能交易等待交易作业空闲,在这个时间里,价格会改变并且可能用这个价格交易 - 数据需要刷新开仓重新计算。

纠正的错误代码将会是以下:
  1. // 智能交易等待交易的时间time (in seconds) whithin which the expert will wait until the trade 
  2. // 交易作业空闲(如果忙)
  3. int MaxWaiting_sec = 30;
  4. int start()
  5.   {
  6.     // 现在检验是否进入市场
  7.     ...
  8.     // 计算止损,赢利和标准手数
  9.     ...
  10.     // 检测交易作业是否空闲
  11.     if(!IsTradeAllowed())
  12.       {
  13.         int StartWaitingTime = GetTickCount();
  14.         Print("交易作业忙!等待空闲...");
  15.         // 无限循环
  16.         while(true)
  17.           {
  18.             // 如过用户中止智能交易,停止业务
  19.             if(IsStopped()) 
  20.               { 
  21.                 Print("智能交易被用户中止!"); 
  22.                 return(-1); 
  23.                }
  24.             // 如果等待时间超过命名变量 
  25.             // MaxWaiting_sec, 停止业务
  26.             if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000) 
  27.               {
  28.                 Print("标准限定(" + MaxWaiting_sec + " sec)超过!");
  29.                 return(-2);
  30.               }
  31.             // 如果交易作业空闲,
  32.             if(IsTradeAllowed())
  33.               {
  34.                 Print("交易作业空闲!");
  35.                 // 刷新市场信息
  36.                 RefreshRates();
  37.                 // 重新计算止损和赢利水平
  38.                 ...
  39.                 // 离开循环状态并开始交易             
  40.                 break;
  41.               }
  42.             // 如过没有条件离开,请 "等待"  0.1秒 
  43.             // 并且重新开始检测
  44.             Sleep(100);
  45.           }
  46.       }
  47.     else
  48.         Print("交易作业空闲!尝试开仓...");
  49.  
  50.     // 尝试开仓
  51.     if(OrderSend(...) < 0) 
  52.         Alert("错误开仓 # ", GetLastError());
  53.  
  54.     return(0);
  55.   }
  56.  

复制代码
对于上面的范例,我们还可以添加:
刷新市场信息(RefreshRates())并且重新计算止损和赢利水平
在超过最大时间限定等待后 MaxWaiting_sec,智能交易将停止业务
以上的这些代码你已经可以使用到你的智能交易中。

现在让我们来谈谈在单独函数中的检测。这将简化在智能交易中的简化和用法。
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // int _IsTradeAllowed( int MaxWaiting_sec = 30 )
  3. //
  4. // 函数检测交易作业状态. R返回代码:
  5. //  1 - 交易作业空闲, 允许交易
  6. //  0 - 交易作业忙,但是将空闲。刷新市场信息后允许交易。
  7. // -1 - 交易作业忙,用户中止等待(智能交易从图表中删除,终端删除,图表周期/货币对改变等等)
  8. // -2 - 交易作业忙,达到最大等待限度 (MaxWaiting_sec). 
  9. //      智能交易禁止交易(检测 "Allow live trading" ).
  10. //
  11. // MaxWaiting_sec - 函数将等待的时间 
  12. // 直到交易作业控点(如果交易作业忙).默认值,30.
  13. /////////////////////////////////////////////////////////////////////////////////
  14. int _IsTradeAllowed(int MaxWaiting_sec = 30)
  15.   {
  16.     // 检测交易作业是否空闲
  17.     if(!IsTradeAllowed())
  18.       {
  19.         int StartWaitingTime = GetTickCount();
  20.         Print("交易作业忙!等待空闲...");
  21.         // 无限循环
  22.         while(true)
  23.           {
  24.             // 如果智能交易被用户中止,停止业务
  25.             if(IsStopped()) 
  26.               { 
  27.                 Print("智能交易被用户中止!"); 
  28.                 return(-1); 
  29.               }
  30.             // 如果等待时间超出指定
  31.             // MaxWaiting_sec 变量 ,停止业务
  32.             if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000)
  33.               {
  34.                 Print("等待限度超过 (" + MaxWaiting_sec + " сек.)!");
  35.                 return(-2);
  36.               }
  37.             // 如果交易作业空闲
  38.             if(IsTradeAllowed())
  39.               {
  40.                 Print("交易作业空闲!");
  41.                 return(0);
  42.               }
  43.             // 如果没有条件离开循环状态,请"等待" 0.1秒 
  44.             // 并且重新开始检测           Sleep(100);
  45.           }
  46.       }
  47.     else
  48.       {
  49.         Print("交易作业空闲!");
  50.         return(1);
  51.       }
  52.   }

复制代码

对于智能交易使用函数的一个模板:
  1. int start()
  2.   {
  3.     // 现在检测是否进入市场
  4.     ...
  5.     // 计算止损,赢利水平和标准手数
  6.     ...
  7.     // 检测交易作业是否空闲
  8.     int TradeAllow = _IsTradeAllowed();
  9.     if(TradeAllow < 0) 
  10.       { 
  11.         return(-1); 
  12.       }
  13.     if(TradeAllow == 0)
  14.       {
  15.         RefreshRates();
  16.         // 重新计算赢利水平和止损水平
  17.         ...
  18.       }
  19.     // 开仓
  20.     if(OrderSend(...) < 0) 
  21.         Alert("错误开仓 # ", GetLastError());
  22.     return(0);
  23.   }

复制代码
由此我们得出以下结论:
函数 IsTradeAllowed()很方便使用,并且对于两到三个智能交易同时运行同样适用。虽然存在一些不足,当很多智能交易同时运行时会出现错误 146。如果"Allow live trading" 禁止,同样可能出现智能交易"hanging" 。
这就是为什么我们考虑解决方案-整体变量作为一个 "信号旗"的原因。

3.客户终端的整体变量
首先是概念:
客户终端的整体变量是所有智能交易,脚本和指标的变量通道。这就意味着整体变量可以由一个智能交易创建,其他的智能交易同样可以使用 。
在 MQL4中提供了以下函数的整体变量:
GlobalVariableCheck() - 检测已经存在的整体变量
GlobalVariableDel() - 删除整体变量
GlobalVariableGet() - 获取整体变量值
GlobalVariableSet() - 创建或修改整体变量
GlobalVariableSetOnCondition() - 用户改变整体变量的指定值。不同于 GlobalVariableSet(),新值将被设定。这个函数是一个创建semaphore的关键。
GlobalVariablesDeleteAll() - 删除所有整体变量 (我们不敢想象它的实用性:))
为什么使用 GlobalVariableSetOnCondition(),而不是联合函数 GlobalVariableGet()和 GlobalVariableSet()呢? 同样的原因:两个函数之前可能重合。这样其他的智能交易则不能插入。这就不使用的原因。

4. 信号旗的基本理念
智能交易准备交易应该检测信号旗的状态。如果信号旗显示 "红色" (整体变量 = 1),意味着其他智能交易在运行中,这样需要等待。如果显示“绿色” (整体变量 = 0),交易可以立即开始 (但不要忘记对其他智能交易设定"红色")。
由此,我们创建了2个函数:一个设定"红色",另一个设定“绿色”。事实上,他们类似。我们尝试地制定了函数的次序(函数TradeIsBusy() 和函数TradeIsNotBusy()) 并且赋予实践。

5. 函数TradeIsBusy()
像我们前面所讲的,这个函数的主要功能是使智能交易等待直至“绿色”显现,并且将其切换成“红色”。另外,我们需要检验是否存在整体变量,并且进行创建。如果不存在。这个检测会从智能交易的函数init() 中进行逻辑性地执行。 但是随后可能被用户删除并且不会有智能交易进行运行。这就是我们将它放置到创建函数中的原因。
所有的这些整体变量的运行都需要伴随信息的展示和错误的生成。 应该记住"hanging":函数的业务时间需要限定。
这就是我们最终得到的:
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // int TradeIsBusy( int MaxWaiting_sec = 30 )
  3. //
  4. // 函数还原TradeIsBusy 值0 - 1.
  5. // 在开启时如果TradeIsBusy = 1 ,函数等待直至 TradeIsBusy 为 0, 
  6. // 随后还原
  7. // 如果TradeIsBusy没有任何整体变量,函数将会自己创建。
  8. // 返回代码:
  9. //  1 - 成功编译。TradeIsBusy整体变量值指定为 1
  10. // -1 - TradeIsBusy = 1 函数在此刻开启,等待用户中止
  11. //      (智能交易从图表中移除,终端被停止,图表周期/货币对被改变等等)
  12. // -2 - TradeIsBusy = 1 函数在此刻开启,等待限定超时
  13. //      (MaxWaiting_sec)
  14. /////////////////////////////////////////////////////////////////////////////////
  15. int TradeIsBusy( int MaxWaiting_sec = 30 )
  16.   {
  17.     // 测试时,没有理由划分交易作业 - 只是终止 
  18.     // 此函数
  19.     if(IsTesting()) 
  20.         return(1);
  21.     int _GetLastError = 0, StartWaitingTime = GetTickCount();
  22.     //+------------------------------------------------------------------+
  23.     //| 检测整体变量是否存在,如果没有,创建整体变量    |
  24.     //+------------------------------------------------------------------+
  25.     while(true)
  26.       {
  27.         // 如果智能交易被用户中止,停止业务
  28.         if(IsStopped()) 
  29.           { 
  30.             Print("智能交易被用户中止!"); 
  31.             return(-1); 
  32.           }
  33.         // 如果等待时间超过指定限定时间 
  34.         // MaxWaiting_sec, 停止业务
  35.         if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000)
  36.           {
  37.             Print("等待时间(" + MaxWaiting_sec + " sec)超出!");
  38.             return(-2);
  39.           }
  40.         // 检测整体变量是否存在
  41.         // 如果不存在离开循环模式,进行改变
  42.         // TradeIsBusy值
  43.         if(GlobalVariableCheck( "TradeIsBusy" )) 
  44.             break;
  45.         else
  46.         // 如果GlobalVariableCheck 返回FALSE, 意味着整体变量不存在或者  
  47.         // 检测中生成错误
  48.           {
  49.             _GetLastError = GetLastError();
  50.             // 如果仍然有错误信息显示,等待0.1 秒, 
  51.             //重新开始检测
  52.             if(_GetLastError != 0)
  53.              {
  54.               Print("TradeIsBusy()-GlobalVariableCheck("TradeIsBusy")-Error #",
  55.                     _GetLastError );
  56.               Sleep(100);
  57.               continue;
  58.              }
  59.           }
  60.         // 如果没有错误,意味着没有整体变量,尝试创建
  61.         // 整体变量
  62.         //如果 the GlobalVariableSet > 0, 说明整体变量成功创建。 
  63.         // 离开函数
  64.         if(GlobalVariableSet( "TradeIsBusy", 1.0 ) > 0 ) 
  65.             return(1);
  66.         else
  67.         // 如果GlobalVariableSet返回值<= 0, 说明有错误
  68.         // 在变量创建时生成
  69.          {
  70.           _GetLastError = GetLastError();
  71.           //显示信息,等待0.1秒,再次尝试
  72.           if(_GetLastError != 0)
  73.             {
  74.               Print("TradeIsBusy()-GlobalVariableSet("TradeIsBusy",0.0 )-Error #",
  75.                     _GetLastError );
  76.               Sleep(100);
  77.               continue;
  78.             }
  79.          }
  80.       }
  81.     //+----------------------------------------------------------------------------------+
  82.     //| 如果函数达到执行点,说明整体变量 | 
  83.     //| 变量退出.                                                                 |
  84.     //| 等待TradeIsBusy 值成为0 并且改变 TradeIsBusy 值为 1 |
  85.     //+----------------------------------------------------------------------------------+
  86.     while(true)
  87.      {
  88.      // 如果智能交易被用户中止,停止业务
  89.      if(IsStopped()) 
  90.        { 
  91.          Print("智能交易被用户中止!"); 
  92.          return(-1); 
  93.        }
  94.      // 如果等待超过限定时间
  95.      // MaxWaiting_sec, 停止业务
  96.      if(GetTickCount() - StartWaitingTime > MaxWaiting_sec * 1000)
  97.        {
  98.          Print("等待时间 (" + MaxWaiting_sec + " sec) 超出!");
  99.          return(-2);
  100.        }
  101.      // 尝试改变 TradeIsBusy的值从 0 - 1
  102.      // 如果成功,离开函数返回1 ("成功编译")
  103.      if(GlobalVariableSetOnCondition( "TradeIsBusy", 1.0, 0.0 )) 
  104.          return(1);
  105.      else
  106.      // 如果失败,可能导致失败的2个原因: TradeIsBusy = 1 (随后等待), 
  107.  
  108.      // 错误生成  (需要我们检测)
  109.       {
  110.       _GetLastError = GetLastError();
  111.       // 如果仍然存在错误,显示信息并且重新尝试
  112.       if(_GetLastError != 0)
  113.       {
  114.    Print("TradeIsBusy()-GlobalVariableSetOnCondition("TradeIsBusy",1.0,0.0 )-Error #",
  115.          _GetLastError );
  116.        continue;
  117.       }
  118.      }
  119.      //如果没有错误,说明TradeIsBusy = 1 (其他智能交易在运行), 
  120.      // 随后显示信息并且等待...
  121.      Comment("等待其他智能交易交易完成...");
  122.      Sleep(1000);
  123.      Comment("");
  124.     }
  125.   }
  126.  

复制代码
在这里可以清楚地看到:
检测整体变量是否存在,如果没有,进行创建
试图改变整体变量的值从 0到 1;如果其值等于0,将开启。
函数可以运行 MaxWaiting_sec,并且不从图表中删除任何商品。
错误信息生成你可以在日志中找到。

6. 函数TradeIsNotBusy()
函数TradeIsNotBusy 解决返回的问题:开启"绿色"。
这项功能没有限定并且不能由用户中止。方式非常简单:如果 "绿色" 关闭,智能交易将不会进行交易。
不会返回任何代码:结果只能被成功编译。
参见下面示例:
  1. /////////////////////////////////////////////////////////////////////////////////
  2. // void TradeIsNotBusy()
  3. //
  4. // 函数设置整体变量 TradeIsBusy 值等于0.
  5. // 如果TradeIsBusy不存在,函数创建。
  6. /////////////////////////////////////////////////////////////////////////////////
  7. void TradeIsNotBusy()
  8.   {
  9.     int _GetLastError;
  10.     // 测试时,交易作业不被划分 - 只是终止 
  11.     // 此函数
  12.     if(IsTesting()) 
  13.       { 
  14.         return(0); 
  15.       }
  16.     while(true)
  17.       {
  18.         // 如果智能交易被用户中止,停止业务
  19.         if(IsStopped()) 
  20.           { 
  21.             Print("智能交易被用户中止!"); 
  22.             return(-1); 
  23.           }
  24.         // 尝试设置整变量值= 0 (创建整体变量)
  25.         // 如果 GlobalVariableSet 返回值 > 0, 说明成功
  26.         // 离开函数
  27.         if(GlobalVariableSet( "TradeIsBusy", 0.0 ) > 0) 
  28.             return(1);
  29.         else
  30.         // 如果GlobalVariableSet 返回值 <= 0, 说明错误生成
  31.         // 显示信息,等待并且尝试重新开始
  32.          {
  33.          _GetLastError = GetLastError();
  34.          if(_GetLastError != 0 )
  35.            Print("TradeIsNotBusy()-GlobalVariableSet("TradeIsBusy",0.0)-Error #", 
  36.                  _GetLastError );
  37.          }
  38.         Sleep(100);
  39.       }
  40.   }

复制代码
7. 在智能交易中的结合使用
现在我们有 3 个函数可以通向交易作业。使他们简单地结合到智能交易中,我们可以创建一个 TradeContext.mq4 文件并且使用 #include (获取文件)。
这是一个使用函数 TradeIsBusy()和函数TradeIsNotBusy()的模板:
  1. #include <TradeContext.mq4>
  2.  
  3. int start()
  4.   {
  5.     // 现在检测是否进入市场
  6.     ...
  7.     // 计算止损水平,赢利水平和标准手数
  8.     ...
  9.     // 等待交易作业空闲并且进入(如果生成错误, 
  10.     // 离开)
  11.     if(TradeIsBusy() < 0) 
  12.         return(-1); 
  13.     // 刷新市场信息
  14.     RefreshRates();
  15.     // 重新计算止损和赢利水平
  16.     ...
  17.     // 开仓
  18.     if(OrderSend(...) < 0) 
  19.       { 
  20.         Alert("错误开仓位置 # ", GetLastError()); 
  21.       }
  22.  
  23.     //设置交易作业空闲
  24.     TradeIsNotBusy();
  25.  
  26.     return(0);
  27.   }
  28.  

复制代码
在使用函数 TradeIsBusy()和函数 TradeIsNotBusy()时,只有一个问题能够产生: 如果在交易作业变成忙后,智能交易从图表中移除,变量 TradeIsBusy将会等于 1。其他的智能交易将不可能运行。
这个问题可以很轻松地解决: 在智能交易在图表中交易时,不从图表中移除;)
在终端停歇时, TradeIsBusy值也有可能不等于0。这种情况,函数 TradeIsNotBusy()从智能交易的函数 init() 被使用。
当然,在任何时间内可以手动改变变量值: 终端内的F3键 。不建议进行使用。

斑马投诉温馨提示:投资有风险,交易需谨慎!

Statement:
The content of this article does not represent the views of fxgecko website. The content is for reference only and does not constitute investment suggestions. Investment is risky, so you should be careful in your choice! If it involves content, copyright and other issues, please contact us and we will make adjustments at the first time!

Related News

您正在访问的是FxGecko网站。 FxGecko互联网及其移动端产品是中国香港特别行政区成立的Hitorank Co.,LIMITED旗下运营和管理的一款面向全球发行的企业资讯査询工具。

您的IP为 中国大陆地区,抱歉的通知您,不能为您提供查询服务,还请谅解。请遵守当地地法律。