《MQL4实用编程》读书笔记(4) - 交易操作的编程:平仓和销仓(撤单)

本章处理3个问题:平仓、撤单、反向(对冲)平仓。

一、平仓

平仓操作使用函数OrderClose()。

函数 OrderClose()

bool OrderClose (int ticket, double lots, double price, int slippage, color Color=CLR_NONE)

若交易成功完成,返回TRUE,否则,返回FALSE。

参数:

ticket - 定单的唯一编号。

lots - 要平仓的手数。允许平仓手数小于定单上的手数,即部分平仓。

price - 平仓价格。具体确定,要符合定单特点和交易规则附录3的规定。否则,平仓请求将被拒绝。设置滑点的,成交价有可能低于平仓请求价。

slippage - 滑点。平仓报价与市场现价之间允许的最大点差。

Color - 在主图上标示平仓价位的箭头颜色。若未用此参数或其值为CLR_NONE,不显示该箭头。

函数 OrderSelect()

为了得到你的各个定单的参数信息,包括现单、挂单、已经平仓的或撤销的等,你应当首先用函数OrderSelect()指定它。

bool OrderSelect(int index, int select, int pool=MODE_TRADES)

OrderSelect 选择定单,以做进一步处理。选择成功,返回TRUE,否则,返回FALSE。

参数:

index - 定单的仓位或编号,由第二个参数区别。

select - 选择方法的标志,其值有2种:

SELECT_BY_POS - 参数'index'是定单在列表中的索引号(起始号为0),

SELECT_BY_TICKET - 参数'index'是定单的唯一编号。

pool - 所选定单的数据来源。当参数'select'的值等于SELECT_BY_POS时,会用到参数'pool'。若参数'select'值为SELECT_BY_TICKET,则不使用参数'pool' ,而由定单编号选择定单。'pool' 可取2种值:

MODE_TRADES (默认值)- "Terminal"窗口"Trade"标签中显示的现单和挂单,是选择对象;

MODE_HISTORY - "Terminal"窗口"Account History"标签中显示的结单和撤单现单和挂单,是选择对象。

为了展示平仓操作,提出一个问题:

问题 28. 写个脚本,将帐户中的定单平仓。平仓的定单,由脚本运行的窗口内的鼠标所在位置确定。

假设有“欧元/美元”的3个现单和“美元/法郎”的1个挂单:


图. 90. 在终端窗口显示几个不同的定单.

要写的脚本应该是这样的:可用鼠标把脚本从"Navigator"窗拖拉到主窗中,松开鼠标按钮时,光标最靠近的开仓价定单,开始平仓。在图91中,会看到光标最靠近卖单4372889。脚本运行时,它就是平仓的对象。


图.91.脚本closeorder.mq4用于选择平仓单。

先看几个相关的内建函数:

int  OrdersTotal(); // 返回现单和挂单的总数

string  OrderSymbol(); // 当前选中的定单涉及的交易对象名称
                       // 必须先用函数OrderSelect()选出定单

int OrderType(); // 返回定单类型:OP_BUY,OP_SELL,OP_BUYLIMIT,
                 // OP_BUYSTOP,OP_SELLLIMIT,OP_SELLSTOPorder.
                 // 必须先用函数OrderSelect()选出定单

double OrderOpenPrice(); // 当前选中的定单的建仓价
                         // 必须先用函数OrderSelect()选出定单

double MathAbs( double value ); // 返回value的绝对值
                                // 可用函数fabs()代替
   
double  NormalizeDouble(
   double  value,      // 要处理的数字
   int     digits      // 小数点后的位数
   );                  // 计算止损、止盈、挂单建仓价时,必须用本函数处理过的数字

int  OrderTicket();  // 当前选中的定单的编号
                     // 必须先用函数OrderSelect()选出定单

double OrderLots(); // 当前选中的定单的手数(交易量)
                    // 必须先用函数OrderSelect()选出定单

void  Sleep(
   int  milliseconds  // 间隔延迟的毫秒数
   );                 // 用于“操盘手”和脚本中,不能用于外建指标中 

下面是解决“问题28”的脚本程序

//--------------------------------------------------------------------------------------
// closeorder.mq4
// The code should be used for educational purpose only.
//--------------------------------------------------------------------------------- 1 --
int start()                                     // 特别函数 'start'
  {
   string Symb=Symbol();                        // 交易对象
   double Dist=1000000.0;                       // 预设
   int Real_Order=-1;                           // 尚无定单
   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;    // 定单上的对象不是所要找的
         int Tip=OrderType();                   // 定单类型
         if (Tip>1) continue;                   // 是挂单
         //----------------------------------------------------------------------- 4 --
         double Price=OrderOpenPrice();         // 定单开仓价
         if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)< //选择出价格最接近的
            NormalizeDouble(Dist,Digits))       
           {
            Dist=MathAbs(Price-Win_Price);      // 新值
            Real_Order=Tip;                     // 有这种类型的定单
            int Ticket=OrderTicket();           // 定单编号
            double Lot=OrderLots();             // 手数
           }
         //----------------------------------------------------------------------- 5 --
        }                                       // 结束定单分析
     }                                          // 结束定单查找
//-------------------------------------------------------------------------------- 6 --
   while(true)                                  // 平仓过程循环
     {
      if (Real_Order==-1)                       // 若没有定单
        {
         Alert("For ",Symb," no market orders available");
         break;                                 // 退出平仓循环
        }
      //-------------------------------------------------------------------------- 7 --
      switch(Real_Order)                        // 定单类型
        {
         case 0: 
            double Price_Cls=Bid;          // 买单Buy
            string Text="Buy ";  // 字符串"Buy"
            break;                         // 退出switch
         case 1: 
            Price_Cls=Ask;                 // 卖单Sell
            Text="Sell ";        // 字符串"Sell"
        }
      Alert("Attempt to close ",Text," ",Ticket,". Awaiting response..");
      bool Ans=OrderClose(Ticket,Lot,Price_Cls,2);// 要求平仓
      //-------------------------------------------------------------------------- 8 --
      if (Ans==true)                            // 完成平仓! :)
        {
         Alert ("Closed order ",Text," ",Ticket);
         break;                                 // 退出平仓循环
        }
      //-------------------------------------------------------------------------- 9 --
      int Error=GetLastError();                 // 平仓失败 :(
      switch(Error)                             // 可以克服的错误
        {
         case 135:
            Alert("The price has changed. 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;                           // 继续下次迭代
        }
      switch(Error)                             // 致命错误
        {
         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);//Other alternatives   
        }
      break;                                    // 退出平仓过程循环
     }
//------------------------------------------------------------------------------- 10 --
   Alert ("The script has finished operations -----------------------------");
   return;                                      // 退出start()
  }
//------------------------------------------------------------------------------- 11 --

二、撤销挂单

用函数 OrderDelete()提出撤销挂单的要求。

函数 OrderDelete()

bool OrderDelete(int ticket, color arrow_color=CLR_NONE)

如果成功撤单,它返回TRUE,否则,返回 FALSE。

参数:

ticket - 定单的唯一编号。

arrow_color - 主图中的箭头颜色。若无此参数,或其值等于CLR_NONE,主图中不显示箭头。

OrderDelete( )不涉及撤单的手数和平仓价格。

定单的撤销,与市场价格无关。也不能部分地撤单。减少挂单手数的办法有2个:撤销现有定单,再建仓减少了手数的新挂单。

撤销挂单的算法,与现价平仓完全相同。只是,撤单不需平仓价格。

示例。撤销挂单的简单脚本。拖拉脚本到主图中,松开鼠标按钮时,与光标所指价位最近的挂单,是撤销的目标。(deleteorder.mq4).
//-------------------------------------------------------------------------------------
// deleteorder.mq4 
// 程序仅用于教学
//-------------------------------------------------------------------------------- 1 --
int start()                                     // 特别函数'start'
  {
   string Symb=Symbol();                        // 交易对象
   double Dist=1000000.0;                       // 预设
   int Limit_Stop=-1;                           // 没有挂单
   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;    // 交易对象不符
         int Tip=OrderType();                   // 定单类型
         if (Tip>2) continue;                   // 现价单
         //----------------------------------------------------------------------- 4 --
         double Price=OrderOpenPrice();         // 定单价格
         if (NormalizeDouble(MathAbs(Price-Win_Price),Digits)> //选出价格最接近的挂单
            NormalizeDouble(Dist,Digits))       
           {
            Dist=MathAbs(Price-Win_Price);      // 新值
            Limit_Stop=Tip;                     // 挂单类型有效
            int Ticket=OrderTicket();           // 挂单编号
           }                                    // if 语句结束
        }                                       // 定单分析结束
     }                                          // 定单查找结束
//-------------------------------------------------------------------------------- 5 --
   switch(Limit_Stop)                           // 按照挂单类型处理
     {
      case 2: string Text= "BuyLimit ";         // BuyLimit字符串
         break;                                 // 退出 'switch'
      case 3: Text= "SellLimit ";               // SellLimit字符串
         break;                                 // 退出 'switch'
      case 4: Text= "BuyStopt ";                // BuyStopt字符串
         break;                                 // 退出 'switch'
      case 5: Text= "SellStop ";                // SellStop字符串
         break;                                 // 退出 'switch'
     }
//-------------------------------------------------------------------------------- 6 --
   while(true)                                  // 平仓过程循环
     {
      if (Limit_Stop==-1)                       // 若无挂单
        {
         Alert("For ",Symb," no pending orders available");
         break;                                 // 退出平仓
        }
      //-------------------------------------------------------------------------- 7 --
      Alert("Attempt to delete ",Text," ",Ticket,". Awaiting response..");
      bool Ans=OrderDelete(Ticket);             // 撤销挂单
      //-------------------------------------------------------------------------- 8 --
      if (Ans==true)                            // 完成撤单! :)
        {
         Alert ("Deleted order ",Text," ",Ticket);
         break;                                 // 退出平仓循环
        }
      //-------------------------------------------------------------------------- 9 --
      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("The order is blocked and is being processed");
            break;                              // 退出 'switch'
         case 145:Alert("Modification is prohibited. ",
                              "The order is too close to the market");
            break;                              // 退出 'switch'
         default: Alert("Occurred error ",Error);// 其他错误
        }
      break;                                    // 退出平仓循环
     }
//------------------------------------------------------------------------------- 10 --
   Alert ("The script has finished operations -----------------------------");
   return;                                      // 退出 start()
  }
//------------------------------------------------------------------------------- 11 --


三、反向(对冲)平仓

反向(对冲)定单 是指对同一交易对象开仓并且交易方向相反的2个现价单。

一对反向定单可以同时平仓,或者,用函数OrderCloseBy(),逐个平仓。反向平仓可以节省(“佣金”)点差。

函数 OrderCloseBy()
bool OrderCloseBy(int ticket, int opposite, color Color=CLR_NONE)

本函数进行对冲平仓操作。若完成对冲平仓,返回TRUE,否则,返回FALSE。

参数:

ticket - 要平仓的定单唯一编号。

opposite - 对冲定单的唯一编号。

Color - 主图中的箭头颜色。若无此参数,或其值等于CLR_NONE,主图中不显示箭头。

对冲平仓无需2个定单的手数相等,而是按手数少的定单平仓。

示例。对冲平仓的简单脚本 ( closeby.mq4).
//--------------------------------------------------------------------
// closeby.mq4 
// 程序仅用于教学
//--------------------------------------------------------------- 1 --
int start()                                     // 特别函数'start'
  {
   string Symb=Symbol();                        // 交易对象
   double Dist=1000000.0;                       // 预设
//--------------------------------------------------------------- 2 --
   while(true)                                  // 处理对冲平仓过程的循环
     {                                          
      double Hedg_Buy = -1.0;                   // 买单Buy的最大成本
      double Hedg_Sell= -1.0;                   // 卖单Sell的最大成本
      for(int i=1; i<=OrdersTotal(); i++)       // 查找定单过程循环
        {
         if(OrderSelect(i-1,SELECT_BY_POS)==true)// 找到一个定单
           {                                    // 分析定单
            //--------------------------------------------------- 3 --
            if (OrderSymbol()!= Symb) continue; // 交易对象不符
            int Tip=OrderType();                // 定单类型
            if (Tip>1) continue;                // 挂单
            //--------------------------------------------------- 4 --
            switch(Tip)                         // 按定单类型分别处理
              {
               case 0:                          // 买单Buy
                  if (OrderLots()>Hedg_Buy)
                    {
                     Hedg_Buy=OrderLots();      // 选择最大成本
                     int Ticket_Buy=OrderTicket();//定单编号
                    }
                  break;                        // 退出 switch
               case 1:                          // 卖单Sell
                  if (OrderLots()>Hedg_Sell)
                    {
                     Hedg_Sell=OrderLots();     // 选择最大成本
                     int Ticket_Sell=OrderTicket();//定单编号
                    }
              }                                 //结束 'switch'
           }                                    //结束定单分析
        }                                       //结束定单查找
      //--------------------------------------------------------- 5 --
      if (Hedg_Buy<0 || Hedg_Sell<0)            // 若无对冲定单
        {                                       
         Alert("All opposite orders are closed :)");
         return;                                // 退出 start()
        }
      //--------------------------------------------------------- 6 --
      while(true)                               // 平仓过程循环
        {
         //------------------------------------------------------ 7 --
         Alert("Attempt to close by. Awaiting response..");
         bool Ans=OrderCloseBy(Ticket_Buy,Ticket_Sell);// Закрытие 
         //------------------------------------------------------ 8 --
         if (Ans==true)                         // 完成平仓! :)
           {
            Alert ("Performed closing by.");
            break;                              // 退出平仓
           }
         //------------------------------------------------------ 9 --
         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("The order is blocked and is being processed");
               break;                           // 退出 'switch'
            case 145:Alert("Modification is prohibited. ",
                                 "The order is too close to market");
               break;                           // 退出 'switch'
            default: Alert("Occurred error ",Error);// 其他错误
           }
         Alert ("The script has finished operations --------------------------");
         return;                                // 退出 start()
        }
     }                                          // 线束处理
//-------------------------------------------------------------- 10 --
  }                                             // 结束 start()
//--------------------------------------------------------------------
  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值