分享一个外汇交易的风控EA

概览

        本人在多年交易经历中,总结出人性中一些难以克服的弱点,编写出了此风控EA。

        目的是帮助交易员规避重仓、频繁交易、亏损加仓等坏习惯,控制单笔及单日亏损比例。

        从而避免账户大亏,早日实现稳定盈利!

        

应用步骤

第一步:复制代码

        创建一个命名为E_Auto_Risk_Monitor_Zsg.mq4的mq4文件(名称可改),复制代码后将其放入脚本目录,比如我本地的目录如下:

        C:\Users\zhong.shuigen\AppData\Roaming\MetaTrader 4 IC Markets\MQL4\Experts

第二步:编译mq4文件,生成执行文件

        

        

第三步:启用EA

        回到MT4界面,导航 - EA交易,双击后运行到某一个(也可多个)货币对上。并保证自动交易按钮已点开(绿色)。

        

        

        

        这样后面的交易就能被EA监控了。

代码

//+------------------------------------------------------------------+
//|                                      E_Auto_Risk_Monitor_Zsg.mq4 |
//|                                                     wouter.zhong |
//|                                                       自动交易EA |
//+------------------------------------------------------------------+
#property copyright "wouter.zhong"
#property link      "自动风控EA-福汇"
#property version   "v2"
 
 
//配置参数
//1 - 亏损限制
double maxLossRatio = 0.15;          //单笔亏损,占账户余额的最大比例
double maxLossRatioOneDay = 0.3;     //总亏损,当日总亏损占账户期初余额的最大比例
 
//2 - 重仓限制
double perMaxMarginRatio = 0.3;      //单笔仓位,最大可用保证金比例
double maxMarginRatio = 0.5;         //总仓位,最大可用保证金比例
 
//3 - 单量限制
int limitCurOrderNums = 3;           //当前单量限制(含挂单)
int limitOrderNums = 10;             //单日总单量限制
 
//4 - 黄金限制
int riskFactor = 1;                  //风险因子(黄金)
int riskPoint = 150;                 //风险止损(黄金)
int riskOrderNums = 10;              //黄金单日下单限制
 
double conceitMarginLimit = 0.2;     //骄傲自负或赌博心态,仓位限制
 
 
string limitMargeNoSym = "";         //重仓限制,不受限币种
string limitOrderNoSym = "";         //单量限制,不受限币种
int limitOrderDays = 1;              //单量限制,期间,单位:day
int slipPoint = 30;                  //滑点数
 
 
 
/** ===========  辅助函数模块 =========== */
 
/**
 * 1)获取最近一个非挂单的订单号
 */
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;
}
 
 
/**
 * 2)获取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;
}
 
 
 
/**
 * 3)获取某期间内的总盈亏
 *    @(不含被删除/未触发的挂单,不含未平仓订单)
 *    @PS:系统时间加6小时,即北京时间
 */
double getPeriodOrderProfit(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 profit = 0;
   int startCount = OrdersHistoryTotal(); //历史总订单数(只返回'账户历史'里的订单)
   
   //Print("天数:"+days+",历史订单数:"+startCount);
 
   for(i=0; i<startCount; i++)   //倒序
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         //Print("编号:"+ i +", 订单号:"+ OrderTicket() + ", 币种:"+ OrderSymbol() +", 订单开仓时间:" + (OrderOpenTime()+6*3600) +", 类型: "+ OrderType() +", 盈亏: "+ OrderProfit());
 
         //统计
         if(OrderOpenTime() < StrToTime(localDayEnd) && OrderOpenTime() >= (StrToTime(localDayEnd) - 86400*days) ){
            if(OrderType()==OP_BUY || OrderType()==OP_SELL){
               profit = profit + OrderProfit();
            }
         }
      }
   }
 
   return profit;
}
 
 
 
/**
 * 4)获取某期间内的出入金
 *    @PS:系统时间加6小时,即北京时间
 */
double getPeriodBalance(int days=5, bool getOutBlance=false, bool getInBlance=false){
   string year = TimeYear(TimeLocal());  //北京时间
   string month = TimeMonth(TimeLocal());
   string day = TimeDay(TimeLocal());
   string localDayEnd = year +"."+ month +"."+ day +" 23:59:59"; //期间截至日的时间
   
   double outBalance = 0;
   double inBalance = 0;
   int i;
   int startCount = OrdersHistoryTotal(); //历史总订单数
 
   for(i=0; i<startCount; i++)   //倒序
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         //统计
         if(OrderOpenTime() < StrToTime(localDayEnd) && OrderOpenTime() >= (StrToTime(localDayEnd) - 86400*days) && OrderType()==6){
            double profit = OrderProfit();
            string date = TimeYear(OrderOpenTime()) +"-"+ TimeMonth(OrderOpenTime()) +"-"+ TimeDay(OrderOpenTime());
            
            if(getOutBlance==true && profit<0){
               //Print("出金--------订单号:" + OrderTicket() + ", 订单类型 "+OrderType()+", 出金金额:"+profit+ ", 日期:"+ date);
               outBalance = outBalance + profit;
            }
            
            if(getInBlance==true && profit>0){
               //Print("入金--------订单号:" + OrderTicket() + ", 订单类型 "+OrderType()+", 入金金额:"+profit+ ", 日期:"+ date);
               inBalance = inBalance + profit;
            }
         }
      }
   }
 
   if(getOutBlance==true){
      return outBalance;
   }else if(getInBlance==true){
      return inBalance;
   }
}
 
 
/**
 * 5)获取某期间内 下单总数
 *    @(不含被删除/未触发的挂单,不含未平仓订单)
 *    @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;
}
 
 
 
 
 
/**
 * 6)判断某币种期间亏损总数
 *    @(不含被删除/未触发的挂单,不含未平仓订单)
 *    @PS:系统时间加6小时,即北京时间
 */
int getPeriodOrderLossNums(int days=1, string symbol=""){
   string year = TimeYear(TimeLocal());  //北京时间
   string month = TimeMonth(TimeLocal());
   string day = TimeDay(TimeLocal());
   string localDayEnd = year +"."+ month +"."+ day +" 23:59:59"; //期间截至日的时间
 
   int i;
   int nums = 0;
   int startCount = OrdersHistoryTotal(); //历史总订单数
 
   for(i=0; i<startCount; i++)   //倒序
   {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         if(symbol != OrderSymbol() || OrderProfit()>=0){
            continue;
         }
         
         //统计
         if(OrderOpenTime() < StrToTime(localDayEnd) && OrderOpenTime() >= (StrToTime(localDayEnd) - 86400*days) ){
            if(OrderType()==OP_BUY || OrderType()==OP_SELL){
               nums++;
            }
         }
      }
   }
 
   return nums;
}
 

/**
订单类型对应值

0	OP_BUY	      买入订单(市价单)
1	OP_SELL	      卖出订单(市价单)
2	OP_BUYLIMIT	   买入限价单(挂单)
3	OP_SELLLIMIT	卖出限价单(挂单)
4	OP_BUYSTOP	   买入止损单(挂单)
5	OP_SELLSTOP	   卖出止损单(挂单)
6	OP_CLOSE	      平仓订单(用于EA内部逻辑,实际交易中不直接使用)

**/
 
 
 
/** ===========  风控函数模块 =========== */
 
/**
 * 1. 限制重仓!
 * @return null
 */
void limitOrderMagin(){
   double accBlance = AccountBalance();   //账户余额
   double accMargin = AccountMargin();    //已用保证金
 
   
   //单笔订单仓位控制
   int j;
   for(j=OrdersTotal()-1; j>=0; j--){
      if(OrderSelect(j, SELECT_BY_POS)){
         if(OrderSymbol() == "XAUUSD"){
            continue;
         }
 
         //挂单不能关闭
         if(OrderType()!=OP_SELL && OrderType()!=OP_BUY){
            continue;
         }
         
         //保证金金额 = 手数乘以1000 (100倍杠杆情况下)
         double OrderOpeBond = OrderLots()*1000;
 
         //平仓
         if(OrderOpeBond > perMaxMarginRatio*accBlance){
            Print("单笔订单-重仓限制_V2,关闭订单:"+ OrderTicket() + ", 已用保证金:" + OrderOpeBond + ", 账户余额:" + accBlance 
            + " -- 币种:" + OrderSymbol() +", 订单盈利:"+ OrderProfit());
 
            OrderClose(
               OrderTicket(),
               OrderLots(),
               MarketInfo(NULL, getModeByType(OrderType())),
               slipPoint
            );
         }   
      }
   }
   
   
   
         
   if(accMargin > maxMarginRatio*accBlance && accBlance>100){
      //最后一个非挂单
      string lastCuOrderTicket = getLastCuTicket();
 
      int i;
      for(i=OrdersTotal()-1; i>=0; i--){
         if(OrderSelect(i, SELECT_BY_POS)){
            //不受限币种判断
            if(limitMargeNoSym != "" && limitMargeNoSym==OrderSymbol()){
               continue;
            }
 
            //挂单不能关闭
            if(OrderType()!=OP_SELL && OrderType()!=OP_BUY){
               continue;
            }
 
            //平仓
            if(OrderTicket() == lastCuOrderTicket){
               Print("重仓限制_V2,关闭订单:"+ lastCuOrderTicket + ", 已用保证金:" + accMargin + ", 账户余额:" + accBlance 
               + " -- 币种:" + OrderSymbol() +", 订单盈利:"+ OrderProfit());
 
               OrderClose(
                  lastCuOrderTicket,
                  OrderLots(),
                  MarketInfo(NULL, getModeByType(OrderType())),
                  slipPoint
               );
              }
           }
        }
     }
  }
 
 
 
/**
 * 2.限制亏损!
 * @return null
 */
void limitOrderLoss(){
   double totalProfit = getPeriodOrderProfit(1);
   //Print("当日总盈亏: " + totalProfit);
 
   int i;
   for(i=OrdersTotal()-1; i>=0; i--){
      if(OrderSelect(i,SELECT_BY_POS)){
         double profit = OrderProfit();
         double balance = AccountBalance();     //账户余额
         //Print("订单货币对: " + OrderSymbol() + ",下单时间:"+TimeHour(OrderOpenTime()));
 
         //1:限制单笔订单亏损(亏损超过账户余额的1-ratio时,强平止损)
         if((profit + balance) < (1-maxLossRatio)*balance) {
            //打印日志
            Print("亏损限制_V2,关闭订单: " + OrderTicket()
                  + ", 币种:"+ OrderSymbol()
                  + ", 手数:"+ OrderLots()
                  + ", 类型:"+ OrderType()
                  + ", 止盈价"+ OrderTakeProfit()
                  + ", 止损价"+ OrderStopLoss()
                  + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
                 );
 
            OrderClose(
               OrderTicket(),
               OrderLots(),
               MarketInfo(OrderSymbol(), getModeByType(OrderType())),
               slipPoint
            );
         }
 
         //2:限制当日总亏损
         if(totalProfit<0 && MathAbs(totalProfit) > maxLossRatioOneDay*(balance + MathAbs(totalProfit))){
            //挂单不提示
            if(OrderType()!=OP_SELL && OrderType()!=OP_BUY){
               continue;
            }
            
            //打印日志
            Print("总亏损限制_V2,关闭订单: " + OrderTicket()
                  + ", 币种:"+ OrderSymbol()
                  + ", 手数:"+ OrderLots()
                  + ", 类型:"+ OrderType()
                  + ", 止盈价"+ OrderTakeProfit()
                  + ", 止损价"+ OrderStopLoss()
                  + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
                  + "。 当日总亏损:"+ totalProfit
                 );
 
            OrderClose(
               OrderTicket(),
               OrderLots(),
               MarketInfo(OrderSymbol(), getModeByType(OrderType())),
               slipPoint
            );
         }
         
         
         //3:限制币种当日亏损订单数
         int lossNums = getPeriodOrderLossNums(1, OrderSymbol());
         //Print(OrderSymbol() + " 当日亏损订单数:" + lossNums);
         /**if(lossNums>=4){
            //打印日志
            Print(OrderSymbol()+" 亏损订单数量限制_V2,关闭订单: " + OrderTicket()
                  + ", 币种:"+ OrderSymbol()
                  + ", 手数:"+ OrderLots()
                  + ", 类型:"+ OrderType()
                  + ", 建仓时间:"+ OrderOpenTime()
                  + ", 止盈价"+ OrderTakeProfit()
                  + ", 止损价"+ OrderStopLoss()
                  + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
                  + "。 当日总亏损:"+ totalProfit
                 );
 
            OrderClose(
               OrderTicket(),
               OrderLots(),
               MarketInfo(OrderSymbol(), getModeByType(OrderType())),
               slipPoint
            );
         }**/
      }
   }
}
 
 
 
/**
 * 3. 限制下单数
 * @ 超出限制后,删除挂单及最新开仓的订单
 * @return null
 * @PS:字符串用双引号,单引号会报错
 */
void limitPeriodOrderNums(){
   //期间历史下单总数(不含被删除的挂单,不含未平仓订单)
   int pOrderAll = getPeriodOrderNums(limitOrderDays, "", limitOrderNoSym);
   int curOrderNums = OrdersTotal();
   //Print("V2_期间已平仓订单总数: "+ pOrderAll + ",现有订单总数:"+ curOrderNums + ",限制订单数:"+limitOrderNums);
   
   
   //历史总订单数
   int startCount = OrdersHistoryTotal();
 
   //最近一个关闭的订单
   int i=0;
   int lastClostOrderTicket = 0;
   for(i=startCount-1; i>=startCount-1; i--) {
      if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
         if(i==startCount-1){
            lastClostOrderTicket = OrderTicket();
         }
      }
   }
   //Print("V2_最近一个关闭的订单: "+ lastClostOrderTicket);
      
      
   //限制当前订单数
   if(curOrderNums > limitCurOrderNums){
      Print("现有订单总数:"+ curOrderNums);
 
      i=0;
      for(i=curOrderNums-1; i>=curOrderNums-1; i++)   //正序(订单号从小到大排序)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
            if(OrderTicket() > lastClostOrderTicket){
               Print("限制当前订单数_V2, 币种:"+ OrderSymbol() +", 订单号:"+OrderTicket() +", 订单盈利:"+ OrderProfit());
 
               //挂单删除
               if(OrderType() == 2 || OrderType() == 3){
                  Print("限制当前订单数_V2,挂单.序号:"+i+ "币种:" + OrderSymbol() + ", 订单号:"+ OrderTicket());
                  OrderDelete(OrderTicket());
               }else{
                  //交易单关闭
                  OrderClose(
                     OrderTicket(),
                     OrderLots(),
                     MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                     slipPoint
                  );
               }
            }
         }
      }
   }
   
 
   //如果期间历史加现单超过了限制,平掉最近一单
   if(curOrderNums + pOrderAll > limitOrderNums){
      //Print("期间已平仓订单总数:"+ pOrderAll + ",现有订单总数:"+ curOrderNums);
 
      i=0;
      for(i=curOrderNums-1; i>=curOrderNums-1; i++)   //正序(订单号从小到大排序)
      {
         if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
 
            //Print("limitPeriodOrderNums - 序号: " + i + ", 订单号:"+OrderTicket()+ "币种: "+ OrderSymbol());
            if(OrderTicket() > lastClostOrderTicket){
               Print("限制订单数_V2, 币种:"+OrderSymbol()+", 订单盈利:"+OrderProfit()+", 订单号:"+OrderTicket()+", 订单类型:"+OrderType());
 
               //挂单删除
               if(OrderType() == 2 || OrderType() == 3){
                  Print("限制订单数_V2,挂单:"+OrderSymbol() + ", 订单号:"+OrderTicket());
                  OrderDelete(OrderTicket());
               }else{
                  //交易单关闭
                  OrderClose(
                     OrderTicket(),
                     OrderLots(),
                     MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                     slipPoint
                  );
               }
            }
         }
      }
   }
}
 
 
 
/**
 * 4. 限制下单时间
 */
void limitOrderOpenTime(){
   //Print("订单数: " + OrdersTotal());
   int i;
   for(i=OrdersTotal()-1; i>=0; i--){
      if(OrderSelect(i, SELECT_BY_POS)){
         double profit = OrderProfit();
         
         //Print(i +"限制下单时间_test,关闭订单: " + OrderTicket() + ",开仓分:"+TimeMinute(OrderOpenTime()));
         
         if(TimeHour(OrderOpenTime())>10 && TimeHour(OrderOpenTime())<50){
            //Print(i +"限制下单分钟_V2,关闭订单: " + OrderTicket() + ",开仓分:"+TimeMinute(OrderOpenTime()));
         }
         
         if(TimeHour(OrderOpenTime())>=21){
            OrderClose(
               OrderTicket(),
               OrderLots(),
               MarketInfo(OrderSymbol(), getModeByType(OrderType())),
               slipPoint
            );
 
            //打印日志
            Print(i +"限制下单时间_V2,关闭订单: " + OrderTicket()
               + ", 币种:"+ OrderSymbol()
               + ", 建仓小时:"+ TimeHour(OrderOpenTime())
               + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
              );
         }
      }
   }
}
 
 
 
/**
 * 5. 限制亏损加仓
 *    应有把握第一个订单不会亏损,
 *    否则当其由盈转亏时,后下的这个订单将被平仓,且一定是亏损的(入场点位不如第一单)
 */
void limitAddOrderWhenLoss(){
   datetime lastOrderTime = 0;         // 最后一个订单的时间戳
   int lastOrderTicket = 0;            // 最后一个订单的编号
   bool hasLoss = false;               // 标记是否存在亏损订单
   double balance = AccountBalance();  //账户余额
 
   // 遍历所有订单
   int total = OrdersTotal();
   int curSymbolLossOrderNums = 0;     //当前货币对下的亏损订单数(以为点差,新单刚开始的利润肯定是负数)
   for(int i=0; i<total; i++){
      if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
         // 检查订单是否属于当前货币对
         if(OrderSymbol() == Symbol()){
            double profit = OrderProfit();
 
            // 检查订单 亏损是否超过 账户余额的比例
            if(profit<0){
               curSymbolLossOrderNums++;
               hasLoss = true;
               // 记录下亏损订单的时间戳和编号
               if(OrderOpenTime() > lastOrderTime){
                  lastOrderTime = OrderOpenTime();
                  lastOrderTicket = OrderTicket();
               }
            }
         }
      }
   }
 
   // 如果存在亏损订单,并且找到了最近下的亏损订单,则关闭它
   if(hasLoss && lastOrderTicket > 0 && curSymbolLossOrderNums>2){
      Print("当前货币对:"+Symbol()+" 存在亏损订单,即将关闭最近下的亏损订单:", lastOrderTicket);
      OrderClose(
         lastOrderTicket,
         OrderLots(),
         MarketInfo(OrderSymbol(), getModeByType(OrderType())),
         slipPoint
      );
      Print("限制亏损加仓_V2。关闭订单:" + lastOrderTicket
         + ", 币种:"+ OrderSymbol()
         + ", 手数:"+ OrderLots()
         + ", 盈亏:" + DoubleToStr(NormalizeDouble(OrderProfit(), 4),4)
      );
               
      /**if(OrderClose(lastOrderTicket, OrderLots(), Bid, 0, clrNONE) > 0){
         Print("限制亏损加仓_V2。关闭订单:" + lastOrderTicket
               + ", 币种:"+ OrderSymbol()
               + ", 手数:"+ OrderLots()
               + ", 盈亏:" + DoubleToStr(NormalizeDouble(OrderProfit(), 4),4)
               + ", 建仓时间:" + OrderOpenTime());
      }else{
         Print("订单关闭失败,错误信息:"+lastOrderTicket, GetLastError());
      }*/
   }
}
 
 
 
/**
* 6. 限制订单亏损时修改止损
*    先定义一个订单结构体,必须写在limitEditStopLoss函数外面,否则结构体数组中都是订单的最新信息,无法判断有无修改止损价
*    再初始化一个固定大小为20的结构体数组
*/
struct OrderStruct{
   int               order_ticket; //订单号
   string            symbol;       //币种
   double            stop_loss;    //止损价
};
 
OrderStruct orderStructArray[30];
 
// 主体代码
void limitEditStopLoss(){
   int arraySize = 0; //数组中结构体实例的数量
 
   int total = OrdersTotal();   //当前订单总数,包括休市中的订单
   //Print("当前订单总数:"+total);
 
   //时间对象
   MqlDateTime timeStruct;
 
   for(int i=0; i<total; i++){
      //if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)){
      if(OrderSelect(i, SELECT_BY_POS)){
         //订单建仓时间
         TimeToStruct(OrderOpenTime(), timeStruct);
         string orderTime = IntegerToString(timeStruct.year) + "." +
                            IntegerToString(timeStruct.mon) + "." +
                            IntegerToString(timeStruct.day) + " " +
                            IntegerToString(timeStruct.hour) + ":" +
                            IntegerToString(timeStruct.min) + ":" +
                            IntegerToString(timeStruct.sec);
 
         //Print("当前订单号:"+OrderTicket()+",币种:"+OrderSymbol()+ ", 建仓时间:"+orderTime+",止损价:"+OrderStopLoss()+", 盈亏:"+OrderProfit()+ ", 类型:"+ OrderType());
 
         //当前订单信息存入结构体 声明结构体变量
         OrderStruct curOrderStruct;
 
         curOrderStruct.order_ticket = OrderTicket();
         curOrderStruct.symbol = OrderSymbol();
         curOrderStruct.stop_loss = OrderStopLoss();
 
         //Print("当前订单号1:"+curOrderStruct.symbol);
  
         //判断是否移动了止损(亏损时)
         if(orderStructArray[i].order_ticket > 0){
            //该订单已在结构体中存在
            OrderStruct existOrderStruct = orderStructArray[i];
 
            //Print("当前订单号2:"+existOrderStruct.order_ticket);
            
            //结构体中的止损价不为0,修改了止损价,订单处于亏损状态
            if(existOrderStruct.order_ticket==OrderTicket() && existOrderStruct.stop_loss>0 && OrderStopLoss()>0
               && existOrderStruct.stop_loss!=OrderStopLoss() && OrderProfit()<0)
            {
               Print("亏损中修改了止损,订单号:"+ existOrderStruct.order_ticket+ ",币种:"+ existOrderStruct.symbol
                     +",止损价:"+existOrderStruct.stop_loss + "。 修改后的止损价:"+ OrderStopLoss()
               );
 
               OrderClose(
                  OrderTicket(),
                  OrderLots(),
                  MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                  slipPoint
               );
               Print("限制亏损中修改止损_V2,关闭订单:" + OrderTicket()
                     + ", 币种:"+ OrderSymbol()
                     + ", 盈亏:" + DoubleToStr(NormalizeDouble(OrderProfit(), 4),4)
               );
                  
 
               /**if(OrderClose(OrderTicket(), OrderLots(), Bid, 0, clrNONE) > 0){
                  Print("限制亏损中修改止损_V2,关闭订单:" + OrderTicket()
                        + ", 币种:"+ OrderSymbol()
                        + ", 盈亏:" + DoubleToStr(NormalizeDouble(OrderProfit(), 4),4)
                  );
               }else{
                  Print("订单关闭失败,错误信息:"+ OrderTicket(), GetLastError());
               }*/
            }
            
         }else{
            //当前订单结构体进入数组,若订单关闭,会从数组中剔除
            if(arraySize < 20){
               if(OrderType()==0 || OrderType()==1){
                  //Print("当前订单进入结构体,订单号:"+OrderTicket() + ",订单类型:" +OrderType());
                  
                  orderStructArray[arraySize] = curOrderStruct;
                  arraySize++;
                 }
            }else{
               Print("订单结构体数组已满!");
            }
         }
      }
   }
}
 
 
 
/**
 * 7. 黄金交易限制!
 * @return null
 */
void limitXauTrement(){
   double balance = AccountBalance();     //账户余额
   double accMargin = AccountMargin();    //已用保证金
   int pOrderAll = getPeriodOrderNums(limitOrderDays, "XAUUSD", limitOrderNoSym);   //黄金当日下单量
   //Print("黄金当日交易量: " + pOrderAll);
   
   
   int i;
   for(i=OrdersTotal()-1; i>=0; i--){
      //黄金单仓位
      if(OrderSelect(i,SELECT_BY_POS)){
         double profit = OrderProfit();
 
         //保证金金额 = 手数乘以开仓价 (100倍杠杆情况下)
         double OrderOpeBond = 0.01*OrderLots()*OrderOpenPrice();
         
         if(OrderSymbol() == "XAUUSD"){
            if(pOrderAll >= riskOrderNums){
               //打印日志
               Print("黄金交易单日下单量控制-关闭订单: " + OrderTicket()+ ",今日已下单数:" + pOrderAll);
   
               OrderClose(
                  OrderTicket(),
                  OrderLots(),
                  MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                  slipPoint
               );
            }
            
            //保证金乘以倍数,是因为黄金风险比其他品质波动更大,而加的风险因子
            if(OrderOpeBond*riskFactor >= maxMarginRatio*balance){
               //打印日志
               Print("黄金交易仓位限制_V2-关闭订单: " + OrderTicket()
                     + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
                     + "。保证金*" + riskFactor + ":" + OrderOpeBond*riskFactor
                     + ",仓位限制:" + maxMarginRatio*balance
                    );
   
               OrderClose(
                  OrderTicket(),
                  OrderLots(),
                  MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                  slipPoint
               );           
            }
            
            double pointGap = MathAbs(OrderClosePrice() - OrderOpenPrice()) * 10;
            //Print("黄金交易-盈/亏点数: " + pointGap + ",利润:" + profit);
            
            //控制XAUUSD亏损不超过设置的点数
            if(profit<0 && pointGap > riskPoint){
               //打印日志
               Print("黄金交易--亏损点数限制-关闭订单: " + OrderTicket()
                     + ", 订单盈亏:"+ DoubleToStr(NormalizeDouble(profit, 4),4)
                     + "。保证金*" + riskFactor + ":" + OrderOpeBond*riskFactor
               );
   
               OrderClose(
                  OrderTicket(),
                  OrderLots(),
                  MarketInfo(OrderSymbol(), getModeByType(OrderType())),
                  slipPoint
               );      
            }
         }
      }
   }
}
 
 
 
/**
 * 8.限制-骄傲自负和赌徒心态
 *   ps: 翻倍后5天内限制仓位10%,亏损50%后5天内限制仓位10%
 * @return null
 */
void limitConceitAndGamble(){  
   int days = 5;
   double totalProfit = getPeriodOrderProfit(days);                        //期间总盈亏
   double totalInBalance = getPeriodBalance(days,false,true);              //期间总入金
   double totalOutBalance = MathAbs(getPeriodBalance(days,true,false));    //期间总出金
   //Print("期间总盈亏:" + totalProfit + ",期间总入金:" +totalInBalance+ ",期间总出金:" +totalOutBalance);
   
   double accBlance = AccountBalance();           //账户余额
   double accMargin = AccountMargin();            //已用保证金
   
   if(totalProfit>0){
      double profitRatio = ceil(100*totalProfit/(accBlance + totalOutBalance - totalProfit));
   }else{
      double lossRatio = ceil(100*totalProfit/(accBlance - totalProfit));
   }
   
   
   bool needClose = false;
   
   //限制仓位
   // 骄傲自负:5天内总盈利占账户余额5成以上(即翻1.2倍),限制仓位20%
   // 赌徒心态:5天内总亏损占超过当前账户余额(即亏损超40%),限制仓位20%
   if(accMargin > conceitMarginLimit*accBlance && accBlance>300){
      if(totalProfit>0 && profitRatio>120){
         needClose = true;
         
         Print("(" +days+ "日)期间总入金:" +totalInBalance+ ", 总出金:" +totalOutBalance+ 
            ". -------- 总盈亏: " + totalProfit + ",账户余额:" +accBlance+ ",盈利比例: " +profitRatio+ "%");
      }else if(totalProfit<0 && lossRatio>40){
         needClose = true;
         
         Print("(" +days+ "日)期间总入金:" +totalInBalance+ ", 总出金:" +totalOutBalance+ 
            ". -------- 总盈亏: " + totalProfit + ",账户余额:" +accBlance+ ",亏损比例: " +lossRatio+ "%");
      }
   }
   
   
   //限制亏损
   if(accBlance>300 && (profitRatio>120 || lossRatio>40)){ 
      //当日总亏损(限制15%)
      double todayProfit = getPeriodOrderProfit(1);
      if(todayProfit<0 && MathAbs(todayProfit) > 0.15*(accBlance - todayProfit)){
          needClose = true;
      }
         
      //每单亏损(限制10%)
      if(OrderProfit()<0 && MathAbs(OrderProfit()) > 0.1*accBlance){
          needClose = true;
      }
   }
   
      
   
   if(needClose){
      string lastCuOrderTicket = getLastCuTicket();   //最后一个非挂单
      int i;
      for(i=OrdersTotal()-1; i>=0; i--){
         if(OrderSelect(i, SELECT_BY_POS)){
            //挂单不能关闭
            if(OrderType()!=OP_SELL && OrderType()!=OP_BUY){
               continue;
            }
 
            //平仓
            if(OrderTicket() == lastCuOrderTicket){
               Print("限制-骄傲自负-控制仓位,关闭订单:"+ lastCuOrderTicket + 
                  ", 已用保证金:" + accMargin + 
                  ", 账户余额:" + accBlance + 
                  ", 币种:" + OrderSymbol() + 
                  ", 订单盈利:"+ OrderProfit()+ 
                  ", 订单序号:" +i);
 
               OrderClose(
                  lastCuOrderTicket,
                  OrderLots(),
                  MarketInfo(NULL, getModeByType(OrderType())),
                  slipPoint
               );
            }
         }
      }
   }
   
}
 
 
 
 
 
/**
 * 报价变动事件
 */
void OnTick(){
   //风控 -- 生命线!!!
   if(AccountEquity()> 0){
      limitOrderMagin();            //1.限制-重仓
      limitOrderLoss();             //2.限制-亏损(单笔/单日/单币种亏损数)
      limitPeriodOrderNums();       //3.限制-下单量
      limitOrderOpenTime();         //4.限制-下单时间
 
      limitAddOrderWhenLoss();      //5.限制-亏损加仓
      limitEditStopLoss();          //6.限制-修改止损
      limitXauTrement();            //7.限制-黄金交易
      limitConceitAndGamble();      //8.限制-骄傲自负&赌徒心态
   }
}
 
 
//+------------------------------------------------------------------+

运用5分钟15分钟的K线波浪能稳定盈利的EA程序。 这个程序如果就按现在的参数不做修改,用以往的数据做测试都能盈利。如果按实时盘进行运行,盈利的概率更大些。这个程序我认为对做外汇有很大帮助,可以克服人性的一些弱点,可以预防随意性的下单、盲目性的加仓、经常性的暴仓。本人炒汇九年常因为舍不得止损或盲目的加仓导致暴仓,使原本盈利丰厚到最后还得亏本;由此本人花了两年的时间根据以往的经验和技术写了这个EA。此EA可以适用于任何货币对,对货币对GU、黄金美元做了以往的数据和模拟盘测试,均能盈利。 程序的一些主要功能: 下单判断: 1、按K线的(5分钟、15分钟、30分钟、4小时)波浪进行综合判断趋势后下单 2、底部或顶部位置进行判断结合K线进行下单 符合上诉条件后下单的例外判断: 1、涨幅够高或跌幅够大,且可能位于反转位置不再下单。 2、在支撑线附近不下单 3、K线图不适合下单的不再下单 4、下降通道的底部不下卖单和上升通道的顶部不下买单 ...... 平单判断: 1、和下单趋势相反方向盈利单平单 2、K线达到顶点或低点的时候平单 3、下单时间较长,非活跃时段把涨幅较小的单平单 4、到压力线平单 5、单边涨跌幅较大,位于顶部时或底部时平单 ..... 锁单和锁单的平单 1、亏损超过阈值时综合判断进行锁单 2、达到锁单平单条件是进行锁单平单 移动止损: 1、移动止损是为了守住盈利,和单纯的移动止损不同。 如设置移动止损值是26,那么盈利27个点时就会设置移动止损值,但下个移动止损值不会一直保持是26 而是会根据图形和K线以及盈利点数进行综合判断来进行移动止损,目的是达盈利最大化。 额外加单: 1、根据原有盈利单进行加单 对手工下单进行跟踪: 1、只要手工下单的备注不为空,那么程序就会自动根据条件平单和锁单以及移动止损。 图形显示: 1、可以在5分钟K线,15分钟K线,30分钟K线,4小时K线以及日K线显示波浪图形 2、在图形界面上显示方向趋势,进行下单提示
简介 这是一个制和管理订单的风控软件,可用于监交易员的成交手数,也避免忘记设置止损和止盈的错误。 很多风控技术工作者在该软件系统的帮助下,节约了大量的工作时间,同时也避免了很多严重性的错误。 同时它可以根据风控参数的设置,关闭其他窗口的EA运行,并执行风控指令。 设计原理 该程序会不断扫描账户的资金与订单信息,并与用户设定的风控参数等信息进行比较。 当账户的的资金状态和订单状态超过风控参数设置的要求时,该系统会立刻进行对账户订单进行平仓,减仓或者清仓的操作。 风控大师的优点 节省风控时间,管理员不需要一直24小时盯着账户信息,通过该软件实现风控操作。 避免人为错误,人工执行风控,可能会出现疏忽性的错误,该系统可以避免人为错误。 提高风控执行,人工风控总是收到心里因素的影响,从而错过了最佳风控时间,该系统可以避免人性的不足。 风控时间及时,人工风控操作会有操作时间差,再瞬息万变的金融市场,速度就是一切,避免因人工风控不足的穿仓。 面板选项选择组合自由使用,易学易用,不用退出软件。 功能简介 净值以上清仓线--当账户的净资产大于该值时,执行清仓操作。 净值以下清仓线--当账户的净资产小于该值时,执行清仓操作。 整体盈利清仓线-- 当账户的浮动盈利大于该值时,执行清仓操作。 整体亏损清仓线-- 当账户的浮动亏损大于该值时,执行清仓操作。 单笔浮盈平仓线-- 当该笔订单浮动盈利大于该值时,执行该订单的平仓。 单笔浮亏平仓线-- 当该笔订单浮动亏损大于该值时,执行该订单的平仓。 盈利关其他窗线-- 当账户的浮动盈利超过该值时,关闭除本软件所在的其他任何窗口。 亏损关其他窗线-- 当账户的浮动亏损超过该值时,关闭除本软件所在的其他任何窗口。 最大单笔仓手数-- 当某笔订单的手数超过该值时候,执行减仓操作,直到符合要求。 最大总持仓手数-- 当账户的总持仓手数超过该值时候,执行减仓操作,直到符合要求。 限制最大止损点-- 当某订单无止损或止损点数超过该值时候,执行修改止损符合要求。 限制最大止盈点--当某订单无止盈或止盈点数超过该值时候,执行修改止盈符合要求。 自动平保盈利点-- 当某订单盈利点超过该值时,修改止损到入场位附近。 跟踪止损距离点-- 订单每次盈利该指定点数,执行跟踪止损。 自动平保盈亏比-- 当某订单的的盈利与止损的比例超过该值时,修改止损到入场价附近。 使用注意事项 本软件运行速度很快,先修改数值,在选择✓,否则数值尚未输入完毕就开始执行风控了。 mt4软件本身固有缺陷,在输入数值时,不要用按键,而是双击直接修改,否则会删除软件界面,如果不幸遇到,那么退出该软件重新加载即可,这种现象在mt5中没有。 软件意义 很多人操盘习惯性不带止损, 重仓,或者疏忽下错手数。执行力不够,到达止盈和止损位时,舍不得平仓了结。 总想赚得更多, 或者再等一等浮亏就会回来,这种赌徒的心理最终会害了自己的。该软件解决交易员执行力问题。 监其他交易员及其他EA的运行状态并执行风控,也可以辅助自己盯盘执行平仓操作。 关于我们 迈达量化专业开发mt4和mt5程序服务,十几年金融与编程经验。 若您有任何软件开发或功能升级等相关需求欢迎联系我们。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值