《MQL4实用编程》读书笔记(5) - 交易操作的编程:修改定单(改仓)

时间:2023-01-08 09:05:38

本章处理2个问题,修改现价单和修改挂单。修改定单的规则参见 Order Characteristics Appendix 3

函数 OrderModify()

用函数 OrderModify(),提出修改现单或挂单的要求。

bool OrderModify(int ticket, double price, double stoploss, double takeprofit, datetime expiration, color arrow_color=CLR_NONE)

本函数修改现单和挂单的参数。若操作成功,返回TRUE,否则,返回FALSE。

参数:

ticket - 定单的唯一编号

price - 挂单或现单新的报价。

stoploss - 新的止损点位。

takeprofit - 新的止盈点位。

expiration - 挂单交易期限。

arrow_color - 在主图中标示修改了止损/止盈点位的箭头颜色。若无此参数,或其等于CLR_NONE,主图中不显示相关箭头。

注意,只能修改挂单的建仓价和交易期限。

如果用未做修改的参数调用本函数,终端会产生出错信息 1 (ERR_NO_RESULT)。有的交易服务器对设置交易期限有限制,若你设定该值不为0,会产生错误信息 147 (ERR_TRADE_EXPIRATION_DENIED) 。

一、修改现价定单

标准的现价定单包括止损和止盈设置。现单的止损/止盈点位可以修改。唯一的限制是,修改后的点位与市场时价的点差,必须符合相关规定 Order CharacteristicsRequirements and Limitations in Making Trades

《MQL4实用编程》读书笔记(5) - 交易操作的编程:修改定单(改仓) 示例。一个简单的“操盘手”,修改止损点位,使得新点位与市场现价的点差,大于原定单(modifystoploss.mq4)
//------------------------------------------------------------------------------------
// modifystoploss.mq4
// 程序仅用于教学
//------------------------------------------------------------------------------------
extern int Tral_Stop=10;                        // 跟踪止损的点位
//------------------------------------------------------------------------------- 1 --
int start()                                     // 特别函数 'start'
  {
   string Symb=Symbol();                        // 交易对象
//------------------------------------------------------------------------------- 2 --
   for(int i=1; i<=OrdersTotal(); i++)          // 查找定单的循环
     {
      if (OrderSelect(i-1,SELECT_BY_POS)==true) // 有定单
        {                                       // 分析定单
         int Tip=OrderType();                   // 定单类型
         if(OrderSymbol()!=Symb||Tip>1)continue;// 不是要找的定单
         double SL=OrderStopLoss();             // 选出的定单的止损点位
         //---------------------------------------------------------------------- 3 --
         while(true)                            // 修改过程循环
           {
            double TS=Tral_Stop;                // 初始化
            int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// 最小点差
            if (TS < Min_Dist)                  // 若小于允许值
               TS=Min_Dist;                     // 以允许值为准
            //------------------------------------------------------------------- 4 --
            bool Modify=false;                  // 不修改
            switch(Tip)                         // 按定单类型分别处理
              {
               case 0 :                         // 买单 Buy
                  if (NormalizeDouble(SL,Digits)< // 若低于交易要求
                     NormalizeDouble(Bid-TS*Point,Digits))
                    {
                     SL=Bid-TS*Point;           // 修改
                     string Text="Buy ";        // Buy 的字符串
                     Modify=true;               // 修改
                    }
                  break;                        // 退出 'switch'
               case 1 :                         // 卖单 Sell
                  if (NormalizeDouble(SL,Digits)> // 若高于交易要求
                     NormalizeDouble(Ask+TS*Point,Digits)
                     || NormalizeDouble(SL,Digits)==0)//或等于0
                    {
                     SL=Ask+TS*Point;           // 修改
                     Text="Sell ";              // Sell 的字符串
                     Modify=true;               // 修改
                    }
              }                                 // 结束 'switch'
            if (Modify==false)                  // 若未做修改
               break;                           // 退出 'while'
            //------------------------------------------------------------------- 5 --
            double TP    =OrderTakeProfit();    // 选出的定单的止盈点位
            double Price =OrderOpenPrice();     // 选出的定单的价格
            int    Ticket=OrderTicket();        // 选出的定单的编号
 
            Alert ("Modification ",Text,Ticket,". Awaiting response..");
            bool Ans=OrderModify(Ticket,Price,SL,TP,0);// 提出修改要求!
            //------------------------------------------------------------------- 6 --
            if (Ans==true)                      // 完成修改! :)
              {
               Alert ("Order ",Text,Ticket," is modified:)");
               break;                           // 退出修改流程
              }
            //------------------------------------------------------------------- 7 --
            int Error=GetLastError();           // 修改失败 :(
            switch(Error)                       // 可克服的错误
              {
               case 130:Alert("Wrong stops. Retrying.");
                  RefreshRates();               // 更新数据
                  continue;                     // 继续迭代
               case 136:Alert("No prices. Waiting for a new tick..");
                  while(RefreshRates()==false)  // 得到新报价
                     Sleep(1);                  // 延迟循环
                  continue;                     // 继续迭代
               case 146:Alert("Trading subsystem is busy. Retrying ");
                  Sleep(500);                   // 简单处理
                  RefreshRates();               // 更新数据
                  continue;                     // 继续迭代
                  // Critical errors
               case 2 : Alert("Common error.");
                  break;                        // 退出 'switch'
               case 5 : Alert("Old version of the client terminal.");
                  break;                        // 退出 'switch'
               case 64: Alert("Account is blocked.");
                  break;                        // 退出 'switch'
               case 133:Alert("Trading is prohibited");
                  break;                        // 退出 'switch'
               default: Alert("Occurred error ",Error);// 其他错误
              }
            break;                              // 退出修改操作
           }                                    // 结束修改操作
         //---------------------------------------------------------------------- 8 --
        }                                       // 结束定单分析
     }                                          // 结束定单查找
//------------------------------------------------------------------------------- 9 --
   return;                                      // 退出 start()
  }
//------------------------------------------------------------------------------ 10 --

二、修改挂单

挂单的修改,与现单的修改略有不同。修改挂单,必须遵守规则Order CharacteristicsRequirements and Limitations in Making Trades

《MQL4实用编程》读书笔记(5) - 交易操作的编程:修改定单(改仓)

示例。以鼠标放置“操盘手”最接近的价位为准,确定要改的定单。 (modifyorderprice.mq4).

//------------------------------------------------------------------------------------
// modifyorderprice.mq4 
// 程序仅用于教学
//------------------------------------------------------------------------------- 1 --
int start()                                     // 特别函数 'start'
  {
   int Tral=10;                                 // 跟踪点差
   string Symb=Symbol();                        // 交易对象
   double Dist=1000000.0;                       // 预设
   double Win_Price=WindowPriceOnDropped();     // 脚本放置于此
//------------------------------------------------------------------------------- 2 --
   for(int i=1; i<=OrdersTotal(); i++)          // 反复查找定单
     {
      if (OrderSelect(i-1,SELECT_BY_POS)==true) // 若有定单
        {                                       // 分析定单:
         //---------------------------------------------------------------------- 3 --
         if (OrderSymbol()!= Symb) continue;    // 交易对象不合要求
         if (OrderType()<2) continue;           // 现价定单
         //---------------------------------------------------------------------- 4 --
         if(NormalizeDouble(MathAbs(OrderOpenPrice()-Win_Price),Digits)
            < NormalizeDouble(Dist,Digits))     // 找出最相接近的
           {
            Dist=MathAbs(OrderOpenPrice()-Win_Price);// New value 
            int    Tip   =OrderType();          // 选出的定单的类型
            int    Ticket=OrderTicket();        // 选出的定单的编号
            double Price =OrderOpenPrice();     // 选出的定单的价格
            double SL    =OrderStopLoss();      // 选出的定单的止损点位
            double TP    =OrderTakeProfit();    // 选出的定单的止盈点位
           }                                    // 结束 'if'
        }                                       // 结束定单分析
     }                                          // 结束查找定单
//------------------------------------------------------------------------------- 5 --
   if (Tip==0)                                  // 没有挂单
     {
      Alert("For ",Symb," no pending orders available");
      return;                                   // 退出程序
     }
//------------------------------------------------------------------------------- 6 --
   while(true)                                  // 平仓过程循环
     {
      RefreshRates();                           // 更新数据
      //------------------------------------------------------------------------- 7 --
      double TS=Tral;                           // 初始化
      int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// 最小点差
      if (TS < Min_Dist)                        // 若小于允许值
         TS=Min_Dist;                           // 以允许值为准
      //------------------------------------------------------------------------- 8 --
      string Text="";                           // 不做修改
      double New_SL=0;
      double New_TP=0;
      switch(Tip)                               // 按定单类型,分别处理
        {
         case 2:                                // BuyLimit挂单
            if (NormalizeDouble(Price,Digits) < // 若超过预设值
                NormalizeDouble(Ask-TS*Point,Digits))
              {
               double New_Price=Ask-TS*Point;   // 新价格
               if (NormalizeDouble(SL,Digits)>0)
                  New_SL=New_Price-(Price-SL);  // 新止损点位
               if (NormalizeDouble(TP,Digits)>0)
                  New_TP=New_Price+(TP-Price);  // 新止盈点位
               Text= "BuyLimit ";               // 修改
              }
            break;                              // 退出 'switch'
         case 3:                                // SellLimit 挂单
            if (NormalizeDouble(Price,Digits) > // 若超出预设值
                NormalizeDouble(Bid+TS*Point,Digits))
              {
               New_Price=Bid+TS*Point;          // 新价格
               if (NormalizeDouble(SL,Digits)>0)
                  New_SL=New_Price+(SL-Price);  // 新止损点位
               if (NormalizeDouble(TP,Digits)>0)
                  New_TP=New_Price-(Price-TP);  // 新止盈点位
               Text= "SellLimit ";              // 修改
              }
            break;                              // 退出 'switch'
         case 4:                                // BuyStopt挂单
            if (NormalizeDouble(Price,Digits) > // 若超出预设值
                NormalizeDouble(Ask+TS*Point,Digits))
              {
               New_Price=Ask+TS*Point;          // 新价格
               if (NormalizeDouble(SL,Digits)>0)
                  New_SL=New_Price-(Price-SL);  // 新止损点位
               if (NormalizeDouble(TP,Digits)>0)
                  New_TP=New_Price+(TP-Price);  // 新止盈点位
               Text= "BuyStopt ";               // 修改
              }
            break;                              // 退出 'switch'
         case 5:                                // SellStop挂单
            if (NormalizeDouble(Price,Digits) < // 若走出预设值
                NormalizeDouble(Bid-TS*Point,Digits))
              {
               New_Price=Bid-TS*Point;          // 新价格
               if (NormalizeDouble(SL,Digits)>0)
                  New_SL=New_Price+(SL-Price);  // 新止损点位
               if (NormalizeDouble(TP,Digits)>0)
                  New_TP=New_Price-(Price-TP);  // 新止盈点位
               Text= "SellStop ";               // 修改
              }
        }
      if (NormalizeDouble(New_SL,Digits)<0)     // 检查止损
         New_SL=0;
      if (NormalizeDouble(New_TP,Digits)<0)     // 检查止盈
         New_TP=0;
      //------------------------------------------------------------------------- 9 --
      if (Text=="")                             // 若未修改
        {
         Alert("No conditions for modification.");
         break;                                 // 退出 'while'
        }
      //------------------------------------------------------------------------ 10 --
      Alert ("Modification ",Text,Ticket,". Awaiting response..");
      bool Ans=OrderModify(Ticket,New_Price,New_SL,New_TP,0);// 修改!
      //------------------------------------------------------------------------ 11 --
      if (Ans==true)                            // 完成修改! :)
        {
         Alert ("Modified order ",Text," ",Ticket," :)");
         break;                                 // 退出平仓
        }
      //------------------------------------------------------------------------ 12 --
      int Error=GetLastError();                 // 修改失败 :(
      switch(Error)                             // 可克服的错误
        {
         case  4: Alert("Trade server is busy. Retrying..");
            Sleep(3000);                        // 简单处理
            continue;                           // 继续迭代
         case 137:Alert("Broker is busy. Retrying..");
            Sleep(3000);                        // 简单处理
            continue;                           // 继续迭代
         case 146:Alert("Trading subsystem is busy. Retrying..");
            Sleep(500);                         // 简单处理
            continue;                           // 继续迭代
        }
      switch(Error)                             // 致命错误
        {
         case 2 : Alert("Common error.");
            break;                              // 退出 'switch'
         case 64: Alert("Account is blocked.");
            break;                              // 退出 'switch'
         case 133:Alert("Trading is prohibited");
            break;                              // 退出 'switch'
         case 139:Alert("Order is blocked and is being processed");
            break;                              // 退出 'switch'
         case 145:Alert("Modification prohibited. ",
                              "Order is too close to the market");
            break;                              // 退出 'switch'
         default: Alert("Occurred error ",Error);// 其他错误
        }
      break;                                    // 退出平仓
     }                                          // 结束平仓
//------------------------------------------------------------------------------ 13 --
   Alert ("The script has completed its operations -----------------------");
   return;                                      // 退出 start()
  }
//------------------------------------------------------------------------------ 14 --