外汇邦外汇论坛 - 中国最大的外汇投资论坛,全球华人外汇交易者交流平台!

 找回密码
 立即注册
查看: 6443|回复: 0

错误146 ("交易作业忙") 和如何处理

[复制链接]

397

主题

458

帖子

5637

积分

论坛元老

Rank: 8Rank: 8

积分
5637
发表于 2015-10-12 17:17:41 | 显示全部楼层 |阅读模式
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.     if(OrderSend(...) < 0)
  51.         Alert("错误开仓 # ", GetLastError());

  52.     return(0);
  53.   }
复制代码

对于上面的范例,我们还可以添加:
刷新市场信息(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.       _GetLastError = GetLastError();
  110.       // 如果仍然存在错误,显示信息并且重新尝试
  111.       if(_GetLastError != 0)
  112.       {
  113.    Print("TradeIsBusy()-GlobalVariableSetOnCondition("TradeIsBusy",1.0,0.0 )-Error #",
  114.          _GetLastError );
  115.        continue;
  116.       }
  117.      }
  118.      //如果没有错误,说明TradeIsBusy = 1 (其他智能交易在运行),
  119.      // 随后显示信息并且等待...
  120.      Comment("等待其他智能交易交易完成...");
  121.      Sleep(1000);
  122.      Comment("");
  123.     }
  124.   }
复制代码
在这里可以清楚地看到:
检测整体变量是否存在,如果没有,进行创建
试图改变整体变量的值从 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. int start()
  3.   {
  4.     // 现在检测是否进入市场
  5.     ...
  6.     // 计算止损水平,赢利水平和标准手数
  7.     ...
  8.     // 等待交易作业空闲并且进入(如果生成错误,
  9.     // 离开)
  10.     if(TradeIsBusy() < 0)
  11.         return(-1);
  12.     // 刷新市场信息
  13.     RefreshRates();
  14.     // 重新计算止损和赢利水平
  15.     ...
  16.     // 开仓
  17.     if(OrderSend(...) < 0)
  18.       {
  19.         Alert("错误开仓位置 # ", GetLastError());
  20.       }

  21.     //设置交易作业空闲
  22.     TradeIsNotBusy();

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

 

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

联系我们|外汇邦外汇论坛

GMT+8, 2024-11-25 15:36

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表