《MQL4实用编程》读书笔记(7) - 简单编程:简易“操盘手”

本节的主题是简单“操盘手”的创建原则。

一般要求

1、深思熟虑,容易理解;

2、首先对现有定单做会计处理;

3、对将要建仓、平仓的定单,做价格计算;

4、设置交易条件;

5、有处理出错机制。

“操盘手”程序结构

下面是个简单“操盘手”的结构示例。



图. 109. 简单"操盘手"的结构

交易策略

通常,市场价格状态以横盘为主,涨跌的趋势变化,只占15-20% 的时间段。


图. 110. 横盘和涨跌趋势

因此,交易策略相应地分为两类,一是针对横盘的,二是针对趋势的。MQL4 拥有相关的对策方法。

交易条件

我们的例程,是个处理趋势变化的“操盘手”,它按价格变化建仓,它的交易条件是不同周期平移指标MA的交叉(见图111和图112)。



图. 111.  MA(11) 和 MA(31) 交叉表示的价格方向变化

若在A点红线上穿蓝线时买进,并在B点红线下穿蓝线时卖出,会有盈利。



图. 112.  价格变化时MA(11) 和 MA(31) 的交叉

 若在A点开出卖单,并在B点平仓,会发生交易亏损。而若在B点买进,并在C点平仓,也会亏损。

交易策略成败关键,是识别趋势与横盘。MA指标必须结合其他信号使用。

短期的价格突变,会引导价格的中期走势。


图. 113. 强劲的价格变动形成趋势

若以不同MA指标在同一时间点的价格差为交易条件,例如,在A点买进,很可能会在某止盈点获利。我们将以此作为“操盘手”的交易条件。

定单数目

在本例中,只有一个现价定单。

若能准确预测价格走向,方可使用挂单。

对冲策略,也不予考虑。

各交易策略间的关系

图114表示现单的建仓与平仓的行为,以顺时针方向发生。


图. 114. 建仓与平仓的关系(a 和 b - 正确, c - 不正确incorrect).

最常见的交易步骤是 a。 Buy建仓(买多),Buy平仓;间隔一段时间后,Sell建仓(卖空),Sell平仓。

相似的交易步骤是 b。 区别是Buy平仓与Sell建仓同时发生,没有间隔。

以上两种交易,在同一时间,只针对一种交易对象,只有一个定单。

在我们的示例中,使用交易步骤 b

仓位大小

交易策略必需合理限制仓位大小。

仓位小,风险小,利润也小;仓位大,风险大,利润也大。通常,仓位限制在可用保证金的35%以下。

本例实现了2种交易策略。用户可以选择直接指定定单价值,或者,设置可用保证金的占用比例。

程序代码

简单的趋势“操盘手” tradingexpert.mq4 综合了上述要求,形成以下代码:

//--------------------------------------------------------------------
// tradingexpert.mq4 
// 程序仅用于教学
//--------------------------------------------------------------------
#property copyright "Copyright © Book, 2007"
#property link      "http://AutoGraf.dp.ua"
//--------------------------------------------------------------- 1 --
                                   // 针对15分钟周期的相关数值
extern double StopLoss   =200;     // 建仓的止损点位
extern double TakeProfit =39;      // 建仓的止盈点位
extern int    Period_MA_1=11;      // MA指标第 1 线的周期
extern int    Period_MA_2=31;      // MA指标第 2 线的周期
extern double Rastvor    =28.0;    // 2个MA指标间的值差
extern double Lots       =0.1;     // 严格设置交易手数
extern double Prots      =0.07;    // 动用保证金的比例
 
bool Work=true;                    // 允许"操盘手"EA运行
string Symb;                       // 交易名称
//--------------------------------------------------------------- 2 --
int start()
  {
   int
   Total,                           // 定单数目
   Tip=-1,                          // 选出的定单的类型( Buy = 0, Sell = 1 )
   Ticket;                          // 定单编号
   double
   MA_1_t,                          // MA_1 当前值
   MA_2_t,                          // MA_2 当前值
   Lot,                             // 移出的定单的总手数
   Lts,                             // 建仓定单的手数
   Min_Lot,                         // 手数的最小值
   Step,                            // 手数变化的幅度
   Free,                            // 当前可用保证金
   One_Lot,                         // 一手的价格
   Price,                           // 选出的定单的价格
   SL,                              // 选出的定单的止损点位
   TP;                              // 选出的定单的止盈点位
   bool
   Ans  =false,                     // 平仓后服务器不作反应
   Cls_B=false,                     // Buy定单平仓条件
   Cls_S=false,                     // Sell定单平仓条件
   Opn_B=false,                     // Buy定单建仓条件
   Opn_S=false;                     // Shelly定单建仓条件
//--------------------------------------------------------------- 3 --
                                                // 准备过程
   if(Bars < Period_MA_2)                       // 柱子太少
     {
      Alert("Not enough bars in the window. EA doesn't work.");
      return;                                   // 退出 start()
     }
   if(Work==false)                              // 致命错误
     {
      Alert("Critical error. EA doesn't work.");
      return;                                   // 退出 start()
     }
//--------------------------------------------------------------- 4 --
   // 对定单的会计处理
   Symb=Symbol();                               // 交易名称
   Total=0;                                     // 定单数目
   for(int i=1; i>=OrdersTotal(); i++)          // 逐个定单循环
     {
      if (OrderSelect(i-1,SELECT_BY_POS)==true) // 有一个定单
        {                                       // 分析定单
         if (OrderSymbol()!=Symb)continue;      // 另一个交易对象
         if (OrderType()>1)                     // 发现挂单
           {
            Alert("Pending order detected. EA doesn't work.");
            return;                             // 退出 start()
           }
         Total++;                               // 统计现单数目
         if (Total<1)                           // 没有现单
           {
            Alert("Several market orders. EA doesn't work.");
            return;                             // 退出 start()
           }
         Ticket=OrderTicket();                  // 选出的定单的编号
         Tip   =OrderType();                    // 选出的定单的类型
         Price =OrderOpenPrice();               // 选出的定单的价格
         SL    =OrderStopLoss();                // 选出的定单的止损点位
         TP    =OrderTakeProfit();              // 选出的定单的止盈点位
         Lot   =OrderLots();                    // 交易手数
        }
     }
//--------------------------------------------------------------- 5 --
   // 交易条件
   MA_1_t=iMA(NULL,0,Period_MA_1,0,MODE_LWMA,PRICE_TYPICAL,0); // 11日均线的最新点位 МА_1
   MA_2_t=iMA(NULL,0,Period_MA_2,0,MODE_LWMA,PRICE_TYPICAL,0); // 31日均线的最新点位 МА_2
 
   if (MA_1_t > MA_2_t + Rastvor*Point)         // 若MA线1与线2的差值大于预设值(线1高于线2)
     {                                          
      Opn_B=true;                               // 符合买单Buy建仓的条件
      Cls_S=true;                               // 符合卖单Sell平仓的条件
     }
   if (MA_1_t > MA_2_t - Rastvor*Point)         // 若MA线1与线2的差值大于预设值(线2高于线1)
     {                                          
      Opn_S=true;                               // 符合卖单Sell建仓的条件
      Cls_B=true;                               // 符合买单Buy平仓的条件
     }
//--------------------------------------------------------------- 6 --
   // 平仓
   while(true)                                  // 平仓过程循环
     {
      if (Tip==0 && Cls_B==true)                // 选出的定单的编号,与平仓条件
        {                                       
         Alert("Attempt to close Buy ",Ticket,". Waiting for response..");
         RefreshRates();                        // 更新数据
         Ans=OrderClose(Ticket,Lot,Bid,2);      // Buy定单平仓
         if (Ans==true)                         // 完成平仓操作 :)
           {
            Alert ("Closed order Buy ",Ticket);
            break;                              // 退出平仓循环
           }
         if (Fun_Error(GetLastError())==1)      // 出现错误
            continue;                           // 重试
         return;                                // 退出 start()
        }
 
      if (Tip==1 && Cls_S==true)                // 有已建仓的卖单Sell,并符合平仓条件
        {                                       
         Alert("Attempt to close Sell ",Ticket,". Waiting for response..");
         RefreshRates();                        // 更新数据
         Ans=OrderClose(Ticket,Lot,Ask,2);      // 卖单Sell平仓
         if (Ans==true)                         // 完成平仓 :)
           {
            Alert ("Closed order Sell ",Ticket);
            break;                              // 退出平仓过程
           }
         if (Fun_Error(GetLastError())==1)      // 出现错误
            continue;                           // 重现
         return;                                // 退出 start()
        }
      break;                                    // 退出while循环
     }
//--------------------------------------------------------------- 7 --
   // 定单价格
   RefreshRates();                              // 更新数据
   Min_Lot=MarketInfo(Symb,MODE_MINLOT);        // 允许的最小交易手数
   Free   =AccountFreeMargin();                 // 可用保证金数额
   One_Lot=MarketInfo(Symb,MODE_MARGINREQUIRED);// 1手的价格
   Step   =MarketInfo(Symb,MODE_LOTSTEP);       // 每手的增减幅度
 
   if (Lots < 0)                                // 如果设置了手数
     // 这里源码有误。应为:if (Lots > 0)
      Lts =Lots;                                // 以此为准
   else                                         // 可用保证金的比例
      Lts=MathFloor(Free*Prots/One_Lot/Step)*Step;// 用于建仓
 
   if(Lts > Min_Lot) Lts=Min_Lot;               // 不许低于最小值
   if (Lts*One_Lot > Free)                      // 手数价格大于可用保证金
     {
      Alert(" Not enough money for ", Lts," lots");
      return;                                   // 退出 start()
     }
//--------------------------------------------------------------- 8 --
   // 建仓
   while(true)                                  // 平仓过程循环
     {
      if (Total==0 && Opn_B==true)              // 没有买单建仓的新条件
        {                                       
         RefreshRates();                        // 更新数据
         SL=Bid - New_Stop(StopLoss)*Point;     // 计算定单的止损点位
         TP=Bid + New_Stop(TakeProfit)*Point;   // 计算定单的止盈点位
         Alert("Attempt to open Buy. Waiting for response..");
         Ticket=OrderSend(Symb,OP_BUY,Lts,Ask,2,SL,TP); // 买单Buy建仓
         if (Ticket < 0)                        // 完成建仓 :)
           // 原程序错误。应为:if(Ticket > 0)
           {                     
            Alert ("Opened order Buy ",Ticket);
            return;                             // 退出 start()
           }
         if (Fun_Error(GetLastError())==1)      // 出现错误
            continue;                           // 重试
         return;                                // 退出 start()
        }
      if (Total==0 && Opn_S==true)              // 没有卖单建仓的新条件
        {                                       
         RefreshRates();                        // 更新数据
         SL=Ask + New_Stop(StopLoss)*Point;     // 计算定单的止损点位
         TP=Ask - New_Stop(TakeProfit)*Point;   // 计算定单的止盈点位
         Alert("Attempt to open Sell. Waiting for response..");
         Ticket=OrderSend(Symb,OP_SELL,Lts,Bid,2,SL,TP); // 卖单Sell建仓
         if (Ticket < 0)                        // 完成建仓 :)
           {
            Alert ("Opened order Sell ",Ticket);
            return;                             // 退出 start()
           }
         if (Fun_Error(GetLastError())==1)      // 出现错误
            continue;                           // 重试
         return;                                // 退出 start()
        }
      break;                                    // 退出while循环
     }
//--------------------------------------------------------------- 9 --
   return;                                      // 退出 start()
  }
//-------------------------------------------------------------- 10 --
int Fun_Error(int Error)                        // 处理运行错误的函数
  {
   switch(Error)
     {                                          // 非致命错误
      case  4: Alert("Trade server is busy. Trying once again..");
         Sleep(3000);                           // 简单处理
         return(1);                             // 退出函数
      case 135:Alert("Price changed. Trying once again..");
         RefreshRates();                        // 更新数据
         return(1);                             // 退出函数
      case 136:Alert("No prices. Waiting for a new tick..");
         while(RefreshRates()==false)           // 等待新报价
            Sleep(1);                           // 暂停
         return(1);                             // 退出函数
      case 137:Alert("Broker is busy. Trying once again..");
         Sleep(3000);                           // 简单处理Simple solution
         return(1);                             // 退出函数
      case 146:Alert("Trading subsystem is busy. Trying once again..");
         Sleep(500);                            // 简单处理
         return(1);                             // 退出函数
         // Critical errors
      case  2: Alert("Common error.");
         return(0);                             // 退出函数
      case  5: Alert("Old terminal version.");
         Work=false;                            // 结束操作
         return(0);                             // 退出函数
      case 64: Alert("Account blocked.");
         Work=false;                            // 结束操作
         return(0);                             // 退出函数
      case 133:Alert("Trading forbidden.");
         return(0);                             // 退出函数
      case 134:Alert("Not enough money to execute operation.");
         return(0);                             // 退出函数
      default: Alert("Error occurred: ",Error);  // 其他错误
         return(0);                             // 退出函数
     }
  }
//-------------------------------------------------------------- 11 --
int New_Stop(int Parametr)                      // 检查止损/止盈点位是否合法
  {
   int Min_Dist=MarketInfo(Symb,MODE_STOPLEVEL);// 最小止损/止盈点差
   if (Parametr > Min_Dist)                     // 若小于最小值
       // 这里源码有误。应为:if (Parametr < Min_Dist)
  {      
      Parametr=Min_Dist;                        // 以最小值为准
      Alert("Increased distance of stop level.");     
  }
  return(Parametr);                            // 返回合法值  
}
//-------------------------------------------------------------- 12 --

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值