分享一个外汇交易的策略EA

概览:

        脚本目录:

        MQL4\Experts\E_Auto_TradeBy_Strategy.mq4

        MQL4\Libraries\E_Common_Help.mq4

        MQL4\Include\E_Common_Help.mqh

        懂的自然知道怎么用。仅供参考,照搬不一定盈利。

        交易有风险,祝早日实现稳定盈利。

代码:

1)E_Auto_TradeBy_Strategy.mq4

//+------------------------------------------------------------------+
//|                                      E_Auto_TradeBy_Strategy.mq4 |
//|                                                     wouter.zhong |
//|                                                         策略交易 |
//+------------------------------------------------------------------+
#property library
#property copyright "wouter.zhong"

#include <E_Common_Help.mqh>              //加载辅助类


//配置参数
int trendLineNums = 10;             //趋势行情K线数
int shakeLineNums = 12;             //震荡行情K线数
int imaBackLineNums = 10;           //均线回踩行情K线数
int slipPoint = 30;                 //滑点数


//1.缺口策略不适用的币种
string strategyGapNoSym[] = {"XAUUSD"};   //黄金缺口经常不回补

//2.三宾策略不适用的币种
string strategyThreeLineNoSym[] = {};

//3.趋势跟进策略不适用的币种
string strategyImaTrendNoSym[] = {};

//4.均线回踩策略不适用的币种
string strategyImaBackNoSym[] = {"USDCHF"};

//5.震荡策略不适用的币种
string strategyShakeNoSym[] = {"XAUUSD", "CADCHF"};

//6.旗型策略不适用的币种
string strategyFlagNoSym[] = {"USDJPY", "USDCHF", "CADCHF"};




/**
 * 辅助函数1:判断币种是否不适用某策略
 * @return bool
 */
bool isSmybolSuitStrategy(string symbol="", int straType=1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //待校验的策略
   string strategyNoSym[]; 
   switch (straType){
       case 1:
         ArrayCopy(strategyNoSym, strategyGapNoSym, 0, 0, WHOLE_ARRAY);       //缺口
         break;
       case 2:
         ArrayCopy(strategyNoSym, strategyThreeLineNoSym, 0, 0, WHOLE_ARRAY); //三宾
         break;
       case 3:
         ArrayCopy(strategyNoSym, strategyImaTrendNoSym, 0, 0, WHOLE_ARRAY);  //趋势跟进
         break;
       case 4:
         ArrayCopy(strategyNoSym, strategyImaBackNoSym, 0, 0, WHOLE_ARRAY);   //均线回踩
         break;
       case 5:
         ArrayCopy(strategyNoSym, strategyShakeNoSym, 0, 0, WHOLE_ARRAY);     //震荡
         break;
       case 6:
         ArrayCopy(strategyNoSym, strategyFlagNoSym, 0, 0, WHOLE_ARRAY);      //旗型
         break;
   }
   
   //数组为空,对所有币种都适用
   int size = ArrayRange(strategyNoSym, 0);
   if(size==0){
      return true;
   }
   
   //循环匹配
   int i;
   for(i=0; i<size; i++){
      if(strategyNoSym[i] == symbol){
         //Print("当前策略限制当前币种:"+ symbol +",策略:"+ straType);
         return false;
      }
   }
   
   return true;
}




/**
 * 策略一:缺口
 * @return null
 */
void makeOrderByGap(string symbol="", int period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 1);
   if(checkIsSuit == false){
      //Print("缺口策略-限制当前币种:"+ symbol);
      return;
   }
   
   //缺口数据
   double gapPrice = getGapInfo(symbol, period, 1);  //缺口价差
   double gapRatio = getGapInfo(symbol, period, 2);  //缺口价差比例
   
   //小于5个点的缺口不值得做
   if(gapRatio <= 0.05){
      return;
   }
  
   
   //检查是否重复下单
   bool checkRepeatOrder = hasRepeatEaOrder(symbol, period, 201);
   if(checkRepeatOrder==true){
      //Print("缺口策略,重复下单。币种:"+ symbol);
      return;
   }
   
   //币种小数位
   int precision = cuSymbolPrecision();
   
   //下挂单
   if(gapRatio > 0.05){
      string orderType;                                                                      //挂单类型
      double orderLots = getMakeLots();                                                      //下单量
      double openPoint = DoubleToStr(iOpen(symbol,period,0) + 1.5*gapPrice, precision);      //挂单价格
      double lossPoint = DoubleToStr(iOpen(symbol,period,0) + 2.5*gapPrice, precision);      //止损价格
      double winPoint  = DoubleToStr(iOpen(symbol,period,0) - gapPrice, precision);          //止盈价格
      string comment = "缺口";                                                               //备注
      int magic = 201;                                                                       //magic number
      string arrowColor = Yellow;                                                            //颜色
      string expiration = TimeToStr(iTime(symbol, period, 0) + 18*60*period);                //有效期
      
      if(gapPrice > 0){ //跳多
         orderType = OP_SELLLIMIT;
      }else{ //跳空
         orderType = OP_BUYLIMIT;
      }
      
      double lossPointNums = MathAbs(100*(openPoint - lossPoint));  //止损点数
      double winPointNums = MathAbs(100*(openPoint - winPoint));    //止盈点数
      
      //打日志
      Print("缺口策略下单,币种:"+ symbol +", 类型:"+ orderType +", 手数:"+ orderLots +", 挂单价格:"+ openPoint +", 止损:"+ lossPoint+
         ", 止损点数:"+ lossPointNums+", 止盈:"+ winPoint +", 止盈点数:"+ winPointNums +",过期时间:"+ expiration + ", gapPrice:"+gapPrice+", gapRatio:"+gapRatio); 
         
      //发邮件 Todo
      
      
      //挂单
      int ticket = OrderSend(symbol, orderType, orderLots, openPoint, slipPoint, lossPoint, winPoint, comment, magic, expiration, arrowColor);
      if(ticket < 0){
          Print("OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
      } 
   }
}



/**
 * 策略二:依据黑/白三宾K线下单
 * @return null
 */
void makeOrderByThreeLine(string symbol="", int period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 2);
   if(checkIsSuit == false){
      //Print("三宾策略-限制当前币种:"+ symbol);
      return;
   }
   
   
   //判断是否白三宾/黑三宾
   int checkRet = checkThreeLineSignal(symbol, period);
   if(checkRet==0){
      //Print("非三宾行情。币种:"+ symbol + ",周期:"+period);
      return;
   }
   
   
   //检查是否重复下单
   bool checkRepeatOrder = hasRepeatEaOrder(symbol, period, 202);
   if(checkRepeatOrder==true){
      //Print("均线策略,重复下单。币种:"+ symbol);
      return;
   }
   
   //币种小数位
   int precision = cuSymbolPrecision();
   
   
   //下单
   if(checkRet > 0){
      string orderType;                            //挂单类型
      double orderLots = getMakeLots();            //下单量
      double openPoint;                            //挂单价
      double lossPoint;                            //止损价
      double winPoint;                             //止盈价
      string comment = "ThreeLine order";          //备注
      int magic = 202;                             //自定义数字;订单的指定号码。可以当作用户定义的识别码使用
      string arrowColor = Yellow;                  //颜色
      
      string str_name;  //策略名
      double blockLength = MathAbs(iClose(symbol,period,1) - iOpen(symbol,period,3)); //三根线总长
      string expiration = TimeToStr(iTime(symbol, period, 0) + 9*60*period);    //有效期
     
      if(checkRet==1){ //白三宾
         orderType = OP_BUY;
         openPoint = DoubleToStr(MathMax(Ask, iOpen(symbol, period, 1)), precision);      //下单价
         lossPoint = DoubleToStr(iOpen(symbol,period,3) - 0.25*blockLength, precision);   //止损价
         winPoint = DoubleToStr(iClose(symbol,period,1) + 1.25*blockLength, precision);   //止盈价
         str_name = comment = "白三宾";
      }else if(checkRet==2){ //黑三宾
         orderType = OP_SELL;
         openPoint = DoubleToStr(MathMin(Bid, iOpen(symbol, period, 1)), precision);
         lossPoint = DoubleToStr(iOpen(symbol,period,3) + 0.25*blockLength, precision);
         winPoint = DoubleToStr(iClose(symbol,period,1) - 1.25*blockLength, precision);
         str_name = comment = "黑三宾";
      }
      
      double lossPointNums = MathAbs(100*(openPoint - lossPoint));  //止损点数
      double winPointNums = MathAbs(100*(openPoint - winPoint));    //止盈点数
      
      //打日志
      Print(str_name +"策略下单,币种:"+ symbol +", 类型:"+ orderType +", 手数:"+ orderLots +", 下单价格:"+ openPoint +", 止损:"+ lossPoint+
         ", 止损点数:"+ lossPointNums+", 止盈:"+ winPoint +", 止盈点数:"+ winPointNums +",过期时间:"+ expiration); 
      
      
      //下单
      int ticket = OrderSend(symbol, orderType, orderLots, openPoint, slipPoint, lossPoint, winPoint, comment, magic, 0, arrowColor);
      if(ticket < 0){
          Print("OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
      }
   }
}



/**
 * 策略三:趋势跟进
 * @return null
 */
void makeOrderByImaTrend(string symbol="", int period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 3);
   if(checkIsSuit == false){
      //Print("均线策略-限制当前币种:"+ symbol);
      return;
   }
   
   
   //判断上升or下跌趋势
   int checkTrend = checkTendencyByIma(symbol, period, trendLineNums); 
   if(checkTrend==0){
      return;
   }
   
   
   //检查是否重复下单
   bool checkRepeatOrder = hasRepeatEaOrder(symbol, period, 203);
   if(checkRepeatOrder==true){
      //Print("均线策略,重复下单。币种:"+ symbol);
      return;
   }
   
   
   //币种小数位
   int precision = cuSymbolPrecision();
   
   
   //下现价单
   if(checkTrend > 0){
      string orderType;                       //挂单类型
      double orderLots = getMakeLots();       //下单量
      double openPoint;                       //挂单价
      double lossPoint;                       //止损价
      double winPoint;                        //止盈价
      string comment = "趋势";                //备注
      int magic = 203;                        //自定义数字
      string arrowColor = Yellow;             //颜色
      
      string orderTypeName;
      string expiration = TimeToStr(iTime(symbol, period, 0) + 9*60*period);    //有效期
      double blockLength = MathAbs(iOpen(symbol, period, trendLineNums) - iOpen(symbol, period, 1));  //K线区域长度

      if(checkTrend==1){ //上升趋势
         orderType = OP_BUY;  //1
         orderTypeName = "BUY";
         openPoint = DoubleToStr(MathMax(Ask, iOpen(symbol, period, 1)), precision);   //下单价
         lossPoint = DoubleToStr(openPoint - 0.5*blockLength, precision);              //止损价
         winPoint = DoubleToStr(openPoint + 1.5*blockLength, precision);               //止盈价
      }else if(checkTrend==2){ //下跌趋势
         orderType = OP_SELL; //0
         orderTypeName = "SELL";
         openPoint = DoubleToStr(MathMin(Bid, iOpen(symbol, period, 1)), precision);
         lossPoint = DoubleToStr(openPoint + 0.5*blockLength, precision);
         winPoint = DoubleToStr(openPoint - 1.5*blockLength, precision);
      }
      
      //止损点数
      double lossPointNums = MathAbs(100*(openPoint - lossPoint));
      
      //止盈点数
      double winPointNums = MathAbs(100*(openPoint - winPoint));
      
      
      //打日志
      Print("趋势策略下单,币种:"+ symbol +", 类型:"+ orderTypeName +", 手数:"+ orderLots +", 建仓:"+ openPoint +", 止损:"+ lossPoint+ 
         ", 止损点数:"+ lossPointNums+", 止盈:"+ winPoint +", 止盈点数:"+ winPointNums +",过期时间:"+ expiration); 
      
      int ticket = OrderSend(symbol, orderType, orderLots, openPoint, slipPoint, lossPoint, winPoint, comment, magic, expiration, arrowColor);
      if(ticket < 0){
          Print("OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
      } 
   }
}



/**
 * 策略四:均线回踩
 * @return null
 */
void makeOrderByImaBack(string symbol="", int period=PERIOD_H4)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 3);
   if(checkIsSuit == false){
      //Print("均线策略-限制当前币种:"+ symbol);
      return;
   }
   
   //检查是否重复下单
   bool checkRepeatOrder = hasRepeatEaOrder(symbol, period, 203);
   if(checkRepeatOrder==true){
      //Print("均线策略,重复下单。币种:"+ symbol);
      return;
   }
   
   //判断上升回踩or下跌回踩
   int checkImaBack = checkImBackType(symbol, period, imaBackLineNums); 
   if(checkImaBack==0){
      return;
   }
   
   
   //币种小数位
   int precision = cuSymbolPrecision();
   
   //区间K线最高价
   double MaxPrice = getGroupKLinesData(symbol, period, imaBackLineNums, 1);
   
   //区间K线最低价
   double MinPrice = getGroupKLinesData(symbol, period, imaBackLineNums, 2);
   
   //区间K线平均长度
   double MeanHeight = DoubleToStr(getGroupKLinesData(symbol, period, imaBackLineNums, 3), precision); 
   
   
   //下现价单
   if(checkImaBack > 0){
      string orderType;                       //挂单类型
      double orderLots = getMakeLots();       //下单量
      double openPoint;                       //挂单价
      double lossPoint;                       //止损价
      double winPoint;                        //止盈价
      string comment = "均线";                //备注
      int magic = 204;                        //自定义数字
      string arrowColor = Yellow;             //颜色
      string expiration = 0;                  //有效期
      
      string orderTypeName;

      if(checkImaBack==1){ //上升回踩
         orderType = OP_BUY;  //1
         orderTypeName = "BUY";
         openPoint = DoubleToStr(MathMax(Ask, iOpen(symbol, period, 1)), precision);   //下单价
         lossPoint = DoubleToStr(openPoint - 2*MeanHeight, precision);                 //止损价
         winPoint = DoubleToStr(MaxPrice + 6*MeanHeight, precision);                   //止盈价
      }else if(checkImaBack==2){ //下跌回踩
         orderType = OP_SELL; //0
         orderTypeName = "SELL";
         openPoint = DoubleToStr(MathMin(Bid, iOpen(symbol, period, 1)), precision);
         lossPoint = DoubleToStr(openPoint + 2*MeanHeight, precision);
         winPoint = DoubleToStr(MinPrice - 6*MeanHeight, precision);
      }
      
      //止损点数
      double lossPointNums = MathAbs(100*(openPoint - lossPoint));
      
      //止盈点数
      double winPointNums = MathAbs(100*(openPoint - winPoint));
      
      
      //打日志
      Print("均线回踩策略下单,币种:"+ symbol +", 类型:"+ orderTypeName +", 手数:"+ orderLots +", 建仓:"+ openPoint +", 止损:"+ lossPoint+ 
         ", 止损点数:"+ lossPointNums+", 止盈:"+ winPoint +", 止盈点数:"+ winPointNums +",过期时间:"+ expiration); 
      
      int ticket = OrderSend(symbol, orderType, orderLots, openPoint, slipPoint, lossPoint, winPoint, comment, magic, expiration, arrowColor);
      if(ticket < 0){
          Print("OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
      } 
   }
}



/**
 * 策略五:震荡
 * @ 往前15根K线,
 * @  最高价 - 最低价 <= 平均K线长度的50%
 * @return null
 */
void makeOrderByShake(string symbol="", int period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 3);
   if(checkIsSuit == false){
      //Print("均线策略-限制当前币种:"+ symbol);
      return;
   }
   
   
   //检查是否重复下单
   bool checkRepeatOrder = hasRepeatEaOrder(symbol, period, 204);
   if(checkRepeatOrder==true){
      //Print("震荡策略,重复下单。币种:"+ symbol);
      return;
   }
   
   
   //K线最高价
   double MaxPrice = getGroupKLinesData(symbol, period, shakeLineNums, 1);
   
   //K线最低价
   double MinPrice = getGroupKLinesData(symbol, period, shakeLineNums, 2);
   
   //K线平均长度
   double MeanHeight = DoubleToStr(getGroupKLinesData(symbol, period, shakeLineNums, 3), 4);  //保留4位小数
   
   //Print("最高价:"+ MaxPrice +",最低价:"+ MinPrice +",最大价差:"+ (MaxPrice-MinPrice) +",平均K线长度:"+MeanHeight +",周期:"+ period +",K线数:"+ shakeLineNums);
   
   //非震荡行情
   double priceGap = MaxPrice - MinPrice;
   if(priceGap > 2*MeanHeight || MeanHeight < 50*Point){
      return;
   }
   
   //币种小数位
   int precision = cuSymbolPrecision();
   
   
   //震荡行情,下挂单(OP_BUYLIMIT)
   string orderType = OP_BUYLIMIT;                                         //挂单类型
   double orderLots = getMakeLots();                                       //下单量
   double openPoint = DoubleToStr(MinPrice + 0.1*MeanHeight, precision);   //挂单价
   double lossPoint = DoubleToStr(MinPrice - 0.5*MeanHeight, precision);   //止损价
   double winPoint = DoubleToStr(MaxPrice - 0.1*MeanHeight, precision);    //止盈价
   string comment = "震荡";                                                //备注
   int magic = 205;                                                        //自定义数字
   string arrowColor = Green;                                              //颜色
   string expiration = TimeToStr(iTime(symbol, period, 0) + 10*60*period);    //有效期
   
   int ticketBuy = OrderSend(symbol,orderType,orderLots,openPoint,slipPoint,lossPoint,winPoint,comment,magic,expiration,arrowColor);
   if(ticketBuy < 0){
       Print("BUYLIMIT OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
   }
   
   double lossPointNums = MathAbs(100*openPoint - lossPoint);  //止损点数
   double winPointNums = MathAbs(100*openPoint - winPoint);    //止盈点数
   
   Print("震荡策略下单,币种:"+ symbol +", 类型:BUYLIMIT, 手数:"+orderLots+", 挂单价格:"+openPoint+", 止损:"+lossPoint+
      ", 止损点数:"+ lossPointNums+", 止盈:"+ winPoint +", 止盈点数:"+ winPointNums +",过期时间:"+ expiration); 
   
   
   //下挂单(OP_SELLLIMIT)
   string orderType_s = OP_SELLLIMIT;                                         //挂单类型
   double orderLots_s = getMakeLots();                                        //下单量
   double openPoint_s = DoubleToStr(MaxPrice - 0.1*MeanHeight, precision);    //挂单价
   double lossPoint_s = DoubleToStr(MaxPrice + 0.5*MeanHeight, precision);    //止损价
   double winPoint_s = DoubleToStr(MinPrice + 0.1*MeanHeight, precision);     //止盈价
   string comment_s = "震荡";                                                 //备注
   int magic_s = 204;                                                         //自定义数字
   string arrowColor_s = Yellow;                                              //颜色
   
   int ticketSell = OrderSend(symbol,orderType_s,orderLots_s,openPoint_s,slipPoint,lossPoint_s,winPoint_s,comment_s,magic_s,expiration,arrowColor_s);
   if(ticketSell < 0){
       Print("SELLLIMIT OrderSend Error Code = #", getErrorMsgByCode(GetLastError()));
   }
   
   //止损点数
   double lossPointNums_s = MathAbs(100*(openPoint_s - lossPoint_s));
   
   //止盈点数
   double winPointNums_s = MathAbs(100*(openPoint_s - winPoint_s));

   Print("震荡策略下单,币种:"+symbol+", 类型:SELLLIMIT, 手数:"+orderLots_s+", 挂单价格:"+openPoint_s+", 止损:"+lossPoint_s+
      ", 止损点数:"+ lossPointNums_s+", 止盈:"+ winPoint_s +", 止盈点数:"+ winPointNums_s +",过期时间:"+ expiration);  

}



/**
 * 策略六:旗型
 * @return null
 */
void makeOrderByFlag(string symbol="", string period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //校验币种是否适用
   bool checkIsSuit = isSmybolSuitStrategy(symbol, 3);
   if(checkIsSuit == false){
      //Print("均线策略-限制当前币种:"+ symbol);
      return;
   }
   
   //Todo
   

}






/**
 * 报价变动事件
 */
void OnTick()
{
   //风控 -- 生命线!!!
   if(AccountEquity()> 0){  
      //makeOrderByGap(Symbol(), PERIOD_H1);           //1.缺口
      //makeOrderByThreeLine(Symbol(), PERIOD_H1);     //2.三宾
      //makeOrderByImaTrend(Symbol(), PERIOD_H1);      //3.趋势跟进
      
      makeOrderByImaBack(Symbol(), PERIOD_H1);         //4.均线回踩
      
      //makeOrderByShake(Symbol(), PERIOD_H1);         //5.震荡
      //makeOrderByFlag(Symbol(), PERIOD_H1);          //6.旗型
      
   }
}

2)E_Common_Help.mq4

//+------------------------------------------------------------------+
//|                                                E_Common_Help.mq4 |
//|                                                     wouter.zhong |
//|                                             辅助函数模块 -- 实现 |
//+------------------------------------------------------------------+
#property copyright "2021,wouter.zhong"
#property library



/**
 * 常用函数列表 
 */
void helpList()
{
   /** 
      # 账户函数
      Print("账户余额:" + MTDAccountBalance());
      Print("账户净值:" + MTDAccountEquity()); 
      Print("已用保证金:" + MTDAccountMargin());
      Print("可用保证金:" +  MTDAccountFreeMargin());
      Print("杠杆:" + MTDAccountLeverage());
      Print("总盈亏:" + MTDAccountProfit()); 
      
      # 数学函数
      Print("比例:" + MathMod(205,100)); //取模
      Print("比例:" + MathFloor(200/100)); //比例 向下取整
      
      # 交易函数
      Print("当前币种:" + Symbol());
      Print("当前币种-昨天开盘价:" + iOpen(Symbol(), PERIOD_D1, 1));
      Print("当前币种-昨天收盘价:" + iClose(Symbol(), PERIOD_D1, 1));
      Print("当前币种-今天开盘价:" + iOpen(Symbol(), PERIOD_D1, 0));
      Print("当前币种-上根K线开盘价(H1):" + iOpen(Symbol(), PERIOD_H1, 1));
      Print("当前币种-上根K线收盘价(H1):" + iClose(Symbol(), PERIOD_H1, 1));
      Print("当前币种-当前K线开盘价(H1):" + iOpen(Symbol(), PERIOD_H1, 0));
      Print("当前币种-当前K线开盘时间(H1):" + iTime(Symbol(), PERIOD_H1, 0));
       
      # 订单函数
      Print("订单编号:" + OrderProfit());
      Print("订单盈亏:" + OrderProfit());
      
      
      # 时间函数
      Print("PERIOD_H1:"+PERIOD_H1);   //输出60
      Print("PERIOD_H1,当前K线开盘时间:"+ iTime(symbol, period, 0));  //1482818400
      Print("PERIOD_H1,当前K线开盘时间,延迟H1:"+ (iTime(symbol, period, 0) + PERIOD_H1)); //1482818460
      Print("PERIOD_H4:"+PERIOD_H4);
      Print("PERIOD_D1:"+PERIOD_D1);
   
   */ 
   
   
}


/**
 * 获取当前挂单数量 
 */
int getPendingOrderNums()
{
   int i;
   int num = 0;
   for(i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderType()!=OP_BUY && OrderType()!=OP_SELL){  //挂单
            num ++;
         }
      }
   }
   
   return num;
}


/**
 * 获取最近一个非挂单的订单号 
 */
string getLastCuTicket(){
   int i;
   int num = 0;
   string orderTicket = "";
   
   for(i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i,SELECT_BY_POS)){
         if(OrderType()==OP_BUY || OrderType()==OP_SELL){
            orderTicket = OrderTicket();
            return orderTicket;
         }
      }
   }
   
   return orderTicket;
}


/**
 * 获取MTDMarketInfo的mode
 */
string getModeByType(string orderType)
{
   string mode;
   
   if(orderType == OP_SELL){
       mode = MODE_ASK;
   }else if(orderType == OP_BUY){
       mode = MODE_BID;
   }else{
       mode = MODE_BID;
   }
   
   return mode;
}


/**
 * 获取缺口点数信息
 * @param smybol 币种
 * @param period 周期级别
 * @param dataType 返回数据类型
 * @return double
 */
double getGapInfo(string symbol="", string period=PERIOD_H1, int dataType=1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   double gapPrice = iOpen(symbol, period, 0) - iClose(symbol, period, 1); //当前K线开盘价 - 上根K线收盘价
   double gapRatio = 100*MathAbs(gapPrice)/iClose(symbol, period, 1);
   
   if(dataType==1){
      return gapPrice;
   }else if(dataType==2){
      return gapRatio;
   }
   
   return 0.00;
}


/**
 * 获取可下单手数
 * @ 依据现有保证金
 * @return int
 */
double getMakeLots()
{
   double lots;
   double lotsBase = 0.01;
   double freeMargin = AccountFreeMargin(); //账户可用保证金
   
   int multiple = MathFloor(freeMargin/100); //倍数向下取整。等于100时值为1
   
   if(freeMargin < 200){
      lots = lotsBase;
   }else if(freeMargin <= 2000){
      lots = multiple*lotsBase;        //2千美元下0.2手,即10%仓位
   }else if(freeMargin <= 10000){
      lots = 0.8*multiple*lotsBase;    //1万美元下0.08手,即8%仓位
   }else if(freeMargin <= 50000){
      lots = 0.6*multiple*lotsBase;    //6%仓位
   }else if(freeMargin <= 200000){
      lots = 0.4*multiple*lotsBase;    //4%仓位
   }else if(freeMargin <= 800000){
      lots = 0.3*multiple*lotsBase;    //3%仓位
   }else{
      lots = 0.2*multiple*lotsBase;    //2%仓位
   }
   
   return lots;
}

/**
 * 获取某期间内 下单总数
 * @(不含被删除/未触发的挂单,不含未平仓订单)
 * @param smybol 筛选的币种
 * @param noSmybol 排除的币种
 * @PS:系统时间加6小时,即北京时间
 */
int getPeriodOrderNums(int days=1, string smybol="", string noSmybol="")
{
   string year = TimeYear(TimeLocal());  //北京时间
   string month = TimeMonth(TimeLocal());
   string day = TimeDay(TimeLocal());
   string localDayEnd = year +"."+ month +"."+ day +" 23:59:59"; //期间截至日的时间
   
   int i;
   int num = 0;
   int startCount = OrdersHistoryTotal(); //历史总订单数
   
   for(i=0; i<startCount; i++){  //倒序
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         //Print("编号:"+ i +", 币种:"+ OrderSymbol() +", 订单开仓时间:" + (OrderOpenTime()+6*3600) +", 类型: "+ OrderType() +", 盈亏: "+ OrderProfit());
         
         //筛选币种判断
         if(smybol != "" && OrderSymbol()!=smybol){
            continue;
         }
         
         //排除币种判断
         if(noSmybol != "" && OrderSymbol()==noSmybol){
            continue;
         }
         
         //统计
         if(OrderOpenTime() < StrToTime(localDayEnd)
            && OrderOpenTime() >= (StrToTime(localDayEnd) - 86400*days)
            && (OrderType()==OP_BUY || OrderType()==OP_SELL))
         {
            num++;
         }
      }
   }
   
   //Print("开始时间:" + TimeToStr((StrToTime(localDayEnd) - 86400*days)) + ";截至时间:" + localDayEnd + "。期间下单总数: "+ num);
   
   return num;
}



/**
 * 获取某期间内的总盈亏
 * @(不含被删除/未触发的挂单,不含未平仓订单)
 * @PS:系统时间加6小时,即北京时间
 */
int getPeriodOrderLoss(int days=1)
{
   string year = TimeYear(TimeLocal());  //北京时间
   string month = TimeMonth(TimeLocal());
   string day = TimeDay(TimeLocal());
   string localDayEnd = year +"."+ month +"."+ day +" 23:59:59"; //期间截至日的时间
   
   int i;
   int lossNum = 0;
   int startCount = OrdersHistoryTotal(); //历史总订单数
   
   for(i=0; i<startCount; i++){  //倒序
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         //Print("编号:"+ i +", 币种:"+ OrderSymbol() +", 订单开仓时间:" + (OrderOpenTime()+6*3600) +", 类型: "+ OrderType() +", 盈亏: "+ OrderProfit());
         
         //统计
         if(OrderOpenTime() < StrToTime(localDayEnd)
            && OrderOpenTime() >= (StrToTime(localDayEnd) - 86400*days)
            && (OrderType()==OP_BUY || OrderType()==OP_SELL))
         {
            lossNum = lossNum + OrderProfit();
         }
      }
   }
   
   
   return lossNum;
}



/**
 * 判断是否白/黑三宾信号
 * @param smybol 币种
 * @param period 周期级别
 * @return bool
 */
int checkThreeLineSignal(string symbol="", string period=PERIOD_H1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   //前第1根K线
   double openPrice_1 = iOpen(symbol, period, 1);      //开盘价
   double closePrice_1 = iClose(symbol, period, 1);    //收盘价
   double pGapRatio_1 =  MathAbs(10000*(closePrice_1 - openPrice_1)/openPrice_1); //价差比例
   
   //前第2根K线
   double openPrice_2 = iOpen(symbol, period, 2);      //开盘价
   double closePrice_2 = iClose(symbol, period, 2);    //收盘价
   double pGapRatio_2 =  MathAbs(10000*(closePrice_2 - openPrice_2)/openPrice_2); //价差比例
   
   //前第3根K线
   double openPrice_3 = iOpen(symbol, period, 3);      //开盘价
   double closePrice_3 = iClose(symbol, period, 3);    //收盘价
   double pGapRatio_3 =  MathAbs(10000*(closePrice_3-openPrice_3)/openPrice_3);   //价差比例
   
   
   //Print("closePrice_1:"+ closePrice_1 +",openPrice_1:"+openPrice_1+ ",价差比例:"+ 10000*(closePrice_1-openPrice_1)/openPrice_1);
   //Print("closePrice_2:"+ closePrice_2 +",openPrice_2:"+openPrice_2+ ",价差比例:"+ 10000*(closePrice_2-openPrice_2)/openPrice_2);
   //Print("closePrice_3:"+ closePrice_3 +",openPrice_3:"+openPrice_3+ ",价差比例:"+ 10000*(closePrice_3-openPrice_3)/openPrice_3);
   
   //iMA线,顺势判断
   double mPrice23_1 = iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, 1);
   double mPrice23_2 = iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, 2);
   double mPrice23_3 = iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, 3);
   
   
   //白三宾(价差3到15最好,杆杠*100)
   if((closePrice_1-openPrice_1>0 && openPrice_1>mPrice23_1 && pGapRatio_1>=3 && pGapRatio_1<=10) &&
      (closePrice_2-openPrice_2>0 && openPrice_2>mPrice23_2 && pGapRatio_2>=3 && pGapRatio_2<=10) && 
      (closePrice_3-openPrice_3>0 && openPrice_3>mPrice23_3 && pGapRatio_3>=3 && pGapRatio_3<=10))
   {
      return 1;
   }
   
   //黑三宾
   if((openPrice_1-closePrice_1>0 && openPrice_1<mPrice23_1 && pGapRatio_1>=3 && pGapRatio_1<=10) &&
      (openPrice_2-closePrice_2>0 && openPrice_2<mPrice23_2 && pGapRatio_2>=3 && pGapRatio_2<=10) &&
      (openPrice_3-closePrice_3>0 && openPrice_3<mPrice23_3 && pGapRatio_3>=3 && pGapRatio_3<=10))
   {
      return 2;
   }

   return 0;
}


/**
 * 判断上升/下跌趋势
 * @param smybol 币种
 * @param period 周期级别
 * @param kLineNums K线根数
 *     double  iMA(
 *        string       symbol,           // 计算指标数据上的货币对名称. NULL表示当前货币对
 *        int          timeframe,        // 时间周期。 可以时间周期列举任意值. 0表示当前图表的时间周期
 *        int          ma_period,        // 平均周期计算
 *        int          ma_shift,         // MA转移。 指标线垂直与图表的时间周期
 *        int          ma_method,        // MA方法。 它可以是其中任意 滑动平均值列举值
 *        int          applied_price,    // 应用的价格。 它可以是应用价格列举的任意值
 *        int          shift             // 显示缓冲采取的值的索引(往前第几根K线)
 *     );
 *     Open[1] 上跟K线的开盘价
 * @return bool
 */
int checkTendencyByIma(string symbol="", string period=PERIOD_H1, int kLineNums=5)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   double maPrice23[];
   double maPrice65[];
   double openPrice[];
   double closePrice[];
   
   //set size
   ArrayResize(maPrice23, kLineNums);
   ArrayResize(maPrice65, kLineNums);
   ArrayResize(openPrice, kLineNums);
   ArrayResize(closePrice, kLineNums);
   
   int i=0;
   for(i=0; i<kLineNums; i++){
      //往前第i+1根K线
      //Print("iMA_Price:"+iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, i+1) + ",索引i:"+i);
      
      ArrayFill(maPrice23, i, 1, iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, i+1));   //23MA线价格
      ArrayFill(maPrice65, i, 1, iMA(symbol, 0, 65, 0, MODE_SMA, PRICE_CLOSE, i+1));   //65MA线价格
      ArrayFill(openPrice, i, 1, Open[i+1]);       //行情线开盘价
      ArrayFill(closePrice, i, 1, Close[i+1]);     //收盘价
      
      //printf("maPrice23[%d] = %.6f", i, maPrice23[i]);
   }
   
   int upTrendNums = 0;    //上升K线数
   int downTrendNums = 0;  //下降K线数
   for(i=0; i<kLineNums; i++){
      //Print("maPrice65_"+ i + ":"+ maPrice65[i] +",maPrice23_"+ i + ":"+ maPrice23[i] +",openPrice"+ i +":"+ openPrice[i]+",closePrice"+ i +":"+ closePrice[i]);
      if(maPrice65[i]<maPrice23[i] && maPrice23[i]<openPrice[i] && openPrice[i]<closePrice[i]){
         upTrendNums++;
      }
      
      if(maPrice65[i]>maPrice23[i] && maPrice23[i]>openPrice[i] && openPrice[i]>closePrice[i]){
         downTrendNums++;
      }
   }
   
   //Print("上升K线数:"+ upTrendNums +",下降K线数:"+ downTrendNums);
   
   //上升趋势
   if(upTrendNums >= MathFloor(kLineNums*0.8)){
      return 1;
   }
   
   //下跌趋势
   if(downTrendNums >= MathFloor(kLineNums*0.8)){
      return 2;
   }
   
   //非趋势
   return 0;
}


/**
 * 判断上升回踩/下跌回踩
 *   判断K线是否在均线 上/下
 * @param smybol 币种
 * @param period 周期级别
 * @param kLineNums K线根数
 * @return bool
 */
int checkImBackType(string symbol="", string period=PERIOD_H1, int kLineNums=10)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   double maPrice23[];
   double maPrice65[];
   double openPrice[];
   double closePrice[];
   
   //set size
   ArrayResize(maPrice23, kLineNums);
   ArrayResize(maPrice65, kLineNums);
   ArrayResize(openPrice, kLineNums);
   ArrayResize(closePrice, kLineNums);
   
   int i=0;
   for(i=0; i<kLineNums; i++){
      //往前第i+1根K线
      ArrayFill(maPrice23, i, 1, iMA(symbol, 0, 23, 0, MODE_SMA, PRICE_CLOSE, i+1));   //23MA线价格
      ArrayFill(maPrice65, i, 1, iMA(symbol, 0, 65, 0, MODE_SMA, PRICE_CLOSE, i+1));   //65MA线价格
      ArrayFill(openPrice, i, 1, Open[i+1]);       //行情线开盘价
      ArrayFill(closePrice, i, 1, Close[i+1]);     //收盘价
   }
   
   int upTrendNums = 0;    //上升K线数
   int downTrendNums = 0;  //下降K线数
   for(i=0; i<kLineNums; i++){
      if(maPrice65[i]<maPrice23[i] && maPrice23[i]<openPrice[i] && openPrice[i]<closePrice[i]){
         upTrendNums++;
      }
      
      if(maPrice65[i]>maPrice23[i] && maPrice23[i]>openPrice[i] && openPrice[i]>closePrice[i]){
         downTrendNums++;
      }
   }
   
   
   //上升回踩(除了往前第一根K线刺破均线,其他都高于均线)
   if(upTrendNums==kLineNums-1 && iLow(symbol, period, 1)<maPrice23[1]){
      return 1;
   }
   
   //下跌回踩(同理)
   if(downTrendNums==kLineNums-1 && iHigh(symbol, period, 1)>maPrice23[1]){
      return 2;
   }
   
   return 0;
}



/**
 * 获取一组K线的数据
 * @ 最高价、最低价、平均K线长度(|收盘-开盘|)
 * @param smybol 币种
 * @param period 周期级别
 * @param kLineNums K线根数i
 * @param dataType 返回数据的类型
 * @return bool
 */
double getGroupKLinesData(string symbol="", string period=PERIOD_H1, int kLineNums=15, int dataType=1)
{
   if(symbol==""){
      symbol = Symbol();
   }
   
   double highPrice[];     //K线最高价
   double lowPrice[];      //K线最低价
   double lineHeight[];    //K线长度
   double lineHeightAll;   //总K线长度
   
   //set size
   ArrayResize(highPrice, kLineNums);
   ArrayResize(lowPrice, kLineNums);
   ArrayResize(lineHeight, kLineNums);
   
   //set value
   int i=1;
   for(i=0; i<kLineNums; i++){
      //往前第i+1根K线
      ArrayFill(highPrice, i, 1, iHigh(symbol, period, i+1));
      ArrayFill(lowPrice, i, 1, iLow(symbol, period, i+1));
      ArrayFill(lineHeight, i, 1, (iHigh(symbol, period, i+1) - iLow(symbol, period, i+1)));  
      
      lineHeightAll += iHigh(symbol, period, i+1) - iLow(symbol, period, i+1);
   }
   
   
   //最高价
   double MaxPrice = highPrice[ArrayMaximum(highPrice, WHOLE_ARRAY, 0)];
   
   //最低价
   double MinPrice = lowPrice[ArrayMinimum(lowPrice, WHOLE_ARRAY, 0)];

   //平均K线长度
   double MeanHeight = lineHeightAll/kLineNums; 
   
   
   //返回数据
   if(dataType>0){
       switch (dataType){
          case 1   :return MaxPrice; break;
          case 2   :return MinPrice; break;
          case 3   :return MeanHeight; break;
       }
   }
   
   return(0.00);
}



/**
 * 根据MQL4错误码,返回错误信息
 * @param code 错误码
 * @return string
 */
string getErrorMsgByCode(int code=0){
    string errorMsg;
    
    if(code>0){
        switch (code){
            case 0   :errorMsg="交易报错码:0 没有错误返回";break;
            case 1   :errorMsg="交易报错码:1 没有错误返回,可能是反复同价修改";break;
            case 2   :errorMsg="交易报错码:2 一般错误";break;
            case 3   :errorMsg="交易报错码:3 交易参数出错";break;
            case 4   :errorMsg="交易报错码:4 交易服务器繁忙";break;
            case 5   :errorMsg="交易报错码:5 客户终端软件版本太旧";break;
            case 6   :errorMsg="交易报错码:6 没有连接交易服务器";break;
            case 7   :errorMsg="交易报错码:7 操作权限不够";break;
            case 8   :errorMsg="交易报错码:8 交易请求过于频繁";break;
            case 9   :errorMsg="交易报错码:9 交易操作故障";break;
            case 64  :errorMsg="交易报错码:64 账户被禁用";break;
            case 65  :errorMsg="交易报错码:65 无效账户";break;
            case 128 :errorMsg="交易报错码:128 交易超时";break;
            case 129 :errorMsg="交易报错码:129 无效报价";break;
            case 130 :errorMsg="交易报错码:130 止损错误";break;
            case 131 :errorMsg="交易报错码:131 交易量错误";break;
            case 132 :errorMsg="交易报错码:132 休市";break;
            case 133 :errorMsg="交易报错码:133 禁止交易";break;
            case 134 :errorMsg="交易报错码:134 资金不足";break;
            case 135 :errorMsg="交易报错码:135 报价发生改变";break;
            case 136 :errorMsg="交易报错码:136 建仓价过期";break;
            case 137 :errorMsg="交易报错码:137 经纪商很忙";break;
            case 138 :errorMsg="交易报错码:138 需要重新报价";break;
            case 139 :errorMsg="交易报错码:139 定单被锁定";break;
            case 140 :errorMsg="交易报错码:140 只允许做买入类型操作";break;
            case 141 :errorMsg="交易报错码:141 请求过多";break;
            case 145 :errorMsg="交易报错码:145 过于接近报价,禁止修改";break;
            case 146 :errorMsg="交易报错码:146 交易繁忙";break;
            case 147 :errorMsg="交易报错码:147 交易期限被经纪商取消";break;
            case 148 :errorMsg="交易报错码:148 持仓单数量超过经纪商的规定";break;
            case 149 :errorMsg="交易报错码:149 禁止对冲";break;
            case 150 :errorMsg="交易报错码:150 FIFO禁则";break;
            case 4000:errorMsg="运行报错码:4000 没有错误返回";break;
            case 4001:errorMsg="运行报错码:4001 函数指针错误";break;
            case 4002:errorMsg="运行报错码:4002 数组越界";break;
            case 4003:errorMsg="运行报错码:4003 调用栈导致内存不足";break;
            case 4004:errorMsg="运行报错码:4004 递归栈溢出";break;
            case 4005:errorMsg="运行报错码:4005 堆栈参数导致内存不足";break;
            case 4006:errorMsg="运行报错码:4006 字符串参数导致内存不足";break;
            case 4007:errorMsg="运行报错码:4007 临时字符串导致内存不足";break;
            case 4008:errorMsg="运行报错码:4008 字符串变量缺少初始化赋值";break;
            case 4009:errorMsg="运行报错码:4009 字符串数组缺少初始化赋值";break;
            case 4010:errorMsg="运行报错码:4010 字符串数组空间不够";break;
            case 4011:errorMsg="运行报错码:4011 字符串太长";break;
            case 4012:errorMsg="运行报错码:4012 因除数为零导致的错误";break;
            case 4013:errorMsg="运行报错码:4013 除数为零";break;
            case 4014:errorMsg="运行报错码:4014 错误的命令";break;
            case 4015:errorMsg="运行报错码:4015 错误的跳转";break;
            case 4016:errorMsg="运行报错码:4016 数组没有初始化";break;
            case 4017:errorMsg="运行报错码:4017 禁止调用DLL ";break;
            case 4018:errorMsg="运行报错码:4018 库文件无法调用";break;
            case 4019:errorMsg="运行报错码:4019 函数无法调用";break;
            case 4020:errorMsg="运行报错码:4020 禁止调用智EA函数";break;
            case 4021:errorMsg="运行报错码:4021 函数中临时字符串返回导致内存不够";break;
            case 4022:errorMsg="运行报错码:4022 系统繁忙";break;
            case 4023:errorMsg="运行报错码:4023 DLL函数调用错误";break;
            case 4024:errorMsg="运行报错码:4024 内部错误";break;
            case 4025:errorMsg="运行报错码:4025 内存不够";break;
            case 4026:errorMsg="运行报错码:4026 指针错误";break;
            case 4027:errorMsg="运行报错码:4027 过多的格式定义";break;
            case 4028:errorMsg="运行报错码:4028 参数计数器越界";break;
            case 4029:errorMsg="运行报错码:4029 数组错误";break;
            case 4030:errorMsg="运行报错码:4030 图表没有响应";break;
            case 4050:errorMsg="运行报错码:4050 参数无效";break;
            case 4051:errorMsg="运行报错码:4051 参数值无效";break;
            case 4052:errorMsg="运行报错码:4052 字符串函数内部错误";break;
            case 4053:errorMsg="运行报错码:4053 数组错误";break;
            case 4054:errorMsg="运行报错码:4054 数组使用不正确";break;
            case 4055:errorMsg="运行报错码:4055 自定义指标错误";break;
            case 4056:errorMsg="运行报错码:4056 数组不兼容";break;
            case 4057:errorMsg="运行报错码:4057 全局变量处理错误";break;
            case 4058:errorMsg="运行报错码:4058 没有发现全局变量";break;
            case 4059:errorMsg="运行报错码:4059 测试模式中函数被禁用";break;
            case 4060:errorMsg="运行报错码:4060 函数未确认";break;
            case 4061:errorMsg="运行报错码:4061 发送邮件错误";break;
            case 4062:errorMsg="运行报错码:4062 String参数错误";break;
            case 4063:errorMsg="运行报错码:4063 Integer参数错误";break;
            case 4064:errorMsg="运行报错码:4064 Double参数错误";break;
            case 4065:errorMsg="运行报错码:4065 数组参数错误";break;
            case 4066:errorMsg="运行报错码:4066 刷新历史数据错误";break;
            case 4067:errorMsg="运行报错码:4067 交易内部错误";break;
            case 4068:errorMsg="运行报错码:4068 没有发现资源文件";break;
            case 4069:errorMsg="运行报错码:4069 不支持资源文件";break;
            case 4070:errorMsg="运行报错码:4070 重复的资源文件";break;
            case 4071:errorMsg="运行报错码:4071 自定义指标没有初始化";break;
            case 4099:errorMsg="运行报错码:4099 文件末尾";break;
            case 4100:errorMsg="运行报错码:4100 文件错误";break;
            case 4101:errorMsg="运行报错码:4101 文件名称错误";break;
            case 4102:errorMsg="运行报错码:4102 打开文件过多";break;
            case 4103:errorMsg="运行报错码:4103 不能打开文件";break;
            case 4104:errorMsg="运行报错码:4104 不兼容的文件";break;
            case 4105:errorMsg="运行报错码:4105 没有选择定单";break;
            case 4106:errorMsg="运行报错码:4106 未知的商品名称";break;
            case 4107:errorMsg="运行报错码:4107 价格无效";break;
            case 4108:errorMsg="运行报错码:4108 报价无效";break;
            case 4109:errorMsg="运行报错码:4109 禁止交易,请尝试修改EA属性";break;
            case 4110:errorMsg="运行报错码:4110 禁止买入类型交易,请尝试修改EA属性";break;
            case 4111:errorMsg="运行报错码:4111 禁止卖出类型交易,请尝试修改EA属性";break;
            case 4200:errorMsg="运行报错码:4200 对象已经存在";break;
            case 4201:errorMsg="运行报错码:4201 未知的对象属性";break;
            case 4202:errorMsg="运行报错码:4202 对象不存在";break;
            case 4203:errorMsg="运行报错码:4203 未知的对象类型";break;
            case 4204:errorMsg="运行报错码:4204 对象没有命名";break;
            case 4205:errorMsg="运行报错码:4205 对象坐标错误";break;
            case 4206:errorMsg="运行报错码:4206 没有指定副图窗口";break;
            case 4207:errorMsg="运行报错码:4207 图形对象错误";break;
            case 4210:errorMsg="运行报错码:4210 未知的图表属性";break;
            case 4211:errorMsg="运行报错码:4211 没有发现主图";break;
            case 4212:errorMsg="运行报错码:4212 没有发现副图";break;
            case 4213:errorMsg="运行报错码:4210 图表中没有发现指标";break;
            case 4220:errorMsg="运行报错码:4220 商品选择错误";break;
            case 4250:errorMsg="运行报错码:4250 消息传递错误";break;
            case 4251:errorMsg="运行报错码:4251 消息参数错误";break;
            case 4252:errorMsg="运行报错码:4252 消息被禁用";break;
            case 4253:errorMsg="运行报错码:4253 消息发送过于频繁";break;
            case 5001:errorMsg="运行报错码:5001 文件打开过多";break;
            case 5002:errorMsg="运行报错码:5002 错误的文件名";break;
            case 5003:errorMsg="运行报错码:5003 文件名过长";break;
            case 5004:errorMsg="运行报错码:5004 无法打开文件";break;
            case 5005:errorMsg="运行报错码:5005 文本文件缓冲区分配错误";break;
            case 5006:errorMsg="运行报错码:5006 文无法删除文件";break;
            case 5007:errorMsg="运行报错码:5007 文件句柄无效";break;
            case 5008:errorMsg="运行报错码:5008 文件句柄错误";break;
            case 5009:errorMsg="运行报错码:5009 文件必须设置为FILE_WRITE";break;
            case 5010:errorMsg="运行报错码:5010 文件必须设置为FILE_READ";break;
            case 5011:errorMsg="运行报错码:5011 文件必须设置为FILE_BIN";break;
            case 5012:errorMsg="运行报错码:5012 文件必须设置为FILE_TXT";break;
            case 5013:errorMsg="运行报错码:5013 文件必须设置为FILE_TXT或FILE_CSV";break;
            case 5014:errorMsg="运行报错码:5014 文件必须设置为FILE_CSV";break;
            case 5015:errorMsg="运行报错码:5015 读文件错误";break;
            case 5016:errorMsg="运行报错码:5016 写文件错误";break;
            case 5017:errorMsg="运行报错码:5017 二进制文件必须指定字符串大小";break;
            case 5018:errorMsg="运行报错码:5018 文件不兼容";break;
            case 5019:errorMsg="运行报错码:5019 目录名非文件名";break;
            case 5020:errorMsg="运行报错码:5020 文件不存在";break;
            case 5021:errorMsg="运行报错码:5021 文件不能被重复写入";break;
            case 5022:errorMsg="运行报错码:5022 错误的目录名";break;
            case 5023:errorMsg="运行报错码:5023 目录名不存在";break;
            case 5024:errorMsg="运行报错码:5024 指定文件而不是目录";break;
            case 5025:errorMsg="运行报错码:5025 不能删除目录";break;
            case 5026:errorMsg="运行报错码:5026 不能清空目录";break;
            case 5027:errorMsg="运行报错码:5027 改变数组大小错误";break;
            case 5028:errorMsg="运行报错码:5028 改变字符串大小错误";break;
            case 5029:errorMsg="运行报错码:5029 结构体包含字符串或者动态数组";break;
        }
    }
    
    return errorMsg; 
}



/**
 * 获取趋势系统-道氏点
 * @ 前20根K线的最低/最高点
 * @param smybol 币种
 * @param period 周期级别
 * @return bool
 */
double getDaoShiPointForTendency(string symbol="", string period=PERIOD_H1)
{
   //Todo
   
   return 0.01;
}


/**
 * 趋势是否结束信息
 * @param smybol 币种
 * @param period 周期级别
 * @return bool
 */
bool isTrendOverSignal(string symbol="", string period=PERIOD_H1)
{
   //Todo
   
   return false;
}


/**
 * 获取币种价格的小数位数
 * @param smybol 币种
 * @return bool
 */
int cuSymbolPrecision()
{
   string symbol = Symbol();
   
   //2位小数的币种
   string symbolPrecision2[] = {"XAUUSD"}; 
   int i;
   for(i=0; i<ArrayRange(symbolPrecision2, 0); i++){
      if(symbolPrecision2[i] == symbol){
         return 2;
      }
   }
   
   //3位小数的币种
   string symbolPrecision3[] = {"USDJPY","AUDJPY","NZDJPY","CADJPY","EURJPY","GBPJPY","CHFJPY","NZDJPY"}; 
   int p;
   for(p=0; p<ArrayRange(symbolPrecision3, 0); p++){
      if(symbolPrecision3[p] == symbol){
         return 3;
      }
   }
   
   return 5; //大部分是5位小数
}


/**
 * 判断是否重复下单
 * @ 对于高并发时无用,
 * @  因:交易指令同一时间全堆到OrderSend时,根本没有已生成订单,因此校验无效
 * @··借鉴PHP的锁机制?
 * @return bool
 */
bool hasRepeatEaOrder(string symbol="", string period=PERIOD_H1, int magicNum=0)
{
   Sleep(2000);   //休眠2秒
   
   //当前K线开盘时间
   string cLineOpenTime = iTime(symbol, period, 0); 
   
   //有比当前K线开盘时间更晚的订单,就是EA单
   //假设前提:不会频繁开仓
   int orderNum = 0; 
   int i;
   for(i=OrdersTotal()-1;i>=0;i--){
      if(OrderSelect(i, SELECT_BY_POS)){
         if(OrderSymbol()==symbol){
            orderNum++;
         }
      }
   }
   
   if(orderNum > 0){
      return true;
   }else{
      return false;
   }
}

3)E_Common_Help.mqh

//+------------------------------------------------------------------+
//|                                                E_Common_Help.mqh |
//|                                                     wouter.zhong |
//|                                              辅助函数模块 -- 声明 |
//+------------------------------------------------------------------+

//辅助类声明
#import "E_Common_Help.ex4"
   void helpList();
   
   //根据MQL4错误码,返回错误信息
   string getErrorMsgByCode(int code); 
   
   //获取MarketInfo的mode
   string getModeByType(string orderType);  
   
   
   
   //获取可下单手数
   double getMakeLots();
   
   //获取某期间内的下单总数
   int getPeriodOrderNums(int days, string smybol, string noSmybol);
   
   //获取某期间内的总盈亏
   int getPeriodOrderLoss(int days);
   
   //获取当前挂单数量
   int getPendingOrderNums();    
   
   //获取最近一个非挂单的订单号
   string getLastCuTicket();                  
   
   
   
   //获取缺口信息
   double getGapInfo(string symbol, string period, int dataType);          

   //判断是否白/黑三宾信号
   int checkThreeLineSignal(string symbol, string period);
              
   //判断上升or下跌趋势
   int checkTendencyByIma(string symbol, string period, int kLineNums);
   
   //获取一组K线的数据
   double getGroupKLinesData(string symbol,string period,int kLineNums,int dataType);
   
   //判断上升回踩or下跌回踩
   int checkImBackType(string symbol, string period, int kLineNums);
   
   
   
   //获取道氏点
   double getDaoShiPointForTendency(string symbol, string period);
   
   //趋势是否反转
   bool isTrendOverSignal(string symbol, string period);
   
   //获取币种价格的小数位数
   int cuSymbolPrecision();
   
   bool hasRepeatEaOrder(string symbol, string period, int magicNum);
   

#import

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
首先,网格交易策略是一种基于价格波动的交易策略,它是通过在价格上下方设置一定的间隔来进行交易的。当价格上升到一定水平时,EA会在上方设置卖出单,并在下方设置买入单,以期望在价格波动中获得利润。 下面是一个基本的网格交易策略EA的示例: ```python import MetaTrader5 as mt5 import time # 设置网格交易策略EA的参数 symbol = "EURUSD" grid_size = 20 # 网格大小 grid_spacing = 50 # 网格间距 lot_size = 0.01 # 每笔交易的手数 # 连接MetaTrader 5客户端 mt5.initialize() account_info = mt5.account_info() print(f"账户余额:{account_info.balance}") # 获取当前价格 symbol_info = mt5.symbol_info(symbol) last_price = mt5.symbol_info_tick(symbol).ask # 初始化网格 buy_orders = [] sell_orders = [] for i in range(-(grid_size//2), (grid_size//2)+1): buy_price = last_price - i*grid_spacing sell_price = last_price + i*grid_spacing buy_order = {"type": mt5.ORDER_TYPE_BUY_LIMIT, "symbol": symbol, "price": buy_price, "lot": lot_size} sell_order = {"type": mt5.ORDER_TYPE_SELL_LIMIT, "symbol": symbol, "price": sell_price, "lot": lot_size} buy_orders.append(buy_order) sell_orders.append(sell_order) # 开始网格交易 while True: # 获取当前价格 symbol_info = mt5.symbol_info(symbol) last_price = mt5.symbol_info_tick(symbol).ask # 更新网格 for i in range(len(buy_orders)): if buy_orders[i]["price"] < last_price - grid_spacing: # 关闭过期的买入单 if mt5.order_send(mt5.ORDER_TYPE_CLOSE_BY, buy_orders[i]["symbol"], buy_orders[i]["lot"], buy_orders[i]["price"], slippage=5) == -1: print("关闭买入单失败") # 更新买入单价格 buy_orders[i]["price"] = last_price - (grid_size-i)*grid_spacing buy_orders[i]["ticket"] = mt5.order_send(buy_orders[i]["type"], buy_orders[i]["symbol"], buy_orders[i]["lot"], buy_orders[i]["price"], slippage=5) if buy_orders[i]["ticket"] == -1: print("开启买入单失败") if sell_orders[i]["price"] > last_price + grid_spacing: # 关闭过期的卖出单 if mt5.order_send(mt5.ORDER_TYPE_CLOSE_BY, sell_orders[i]["symbol"], sell_orders[i]["lot"], sell_orders[i]["price"], slippage=5) == -1: print("关闭卖出单失败") # 更新卖出单价格 sell_orders[i]["price"] = last_price + (grid_size-i)*grid_spacing sell_orders[i]["ticket"] = mt5.order_send(sell_orders[i]["type"], sell_orders[i]["symbol"], sell_orders[i]["lot"], sell_orders[i]["price"], slippage=5) if sell_orders[i]["ticket"] == -1: print("开启卖出单失败") time.sleep(1) ``` 上述代码中,我们首先连接了MetaTrader 5客户端,并设置了网格交易策略EA的参数。然后,我们获取了当前价格,并初始化了网格。接着,我们在一个无限循环中不断更新网格,如果价格超出了某一网格的范围,我们就关闭过期的订单并打开新的订单。 需要注意的是,这只是一个简单的网格交易策略EA示例,实际的交易策略需要根据市场情况进行调整和优化。此外,MetaTrader 5中还有许多其他的交易函数和指标,可以用于开发更加复杂的交易策略

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值