请问如何判断历史订单是否是连续亏损的?哪位大神知道用MQL5怎样写吗?

 

历史订单有亏损的,有盈利的,请问一下如何判断是连续亏损的?

 
ken138888:
历史订单有亏损的,有盈利的,请问一下如何判断是连续亏损的?

呵呵,又遇到你了,

这个逻辑很简单

搜索全部历史,如果是亏损,就让一个计数变量+1,如果出现一次盈利就让这个计数变量清零

//+------------------------------------------------------------------+
//|                                                        Test4.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#define Ask    SymbolInfoDouble(_Symbol, SYMBOL_ASK) // 定义当前货币对买入价
#define Bid    SymbolInfoDouble(_Symbol, SYMBOL_BID) // 定义当前货币对卖出价
#include <Trade\Trade.mqh>                           // 调用MQL5交易库文件
CTrade        m_trade;                               // 创建交易类对象
CPositionInfo m_pos;                                 // 创建订单类对象
CDealInfo     m_deal;                                // 创建成交类对象
input long    Magic             = 1234;
input int     DailyTotal        = 3;
input bool    AllowTrailingStop = true;
input double  StartTrailing     = 200;
input int     MaxLoss           = 3;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create timer
   EventSetMillisecondTimer(100);        // 设置计时器 1秒=1000 毫秒, 这里设置100毫秒, 即1秒运行10次
   m_trade.SetExpertMagicNumber(Magic);  // 设置魔术编号, 只管理此EA开设的单子
   m_trade.SetAsyncMode(true);           // 设置异步交易模式, 这样程序就不用等待每个交易操作的结果
   m_trade.SetDeviationInPoints(INT_MAX);// 设置允许的最大滑点
//---
   return(INIT_SUCCEEDED);               // 返回初始化成功
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();                     // 关闭计时器
   Comment("");                          // 清空显示
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
   if(DailyTradeLimit(DailyTotal))
     {
      //--- 你的继续交易的代码
     }
   else
     {
      //--- 停止交易的代码
     }
//---
   if(AllowTrailingStop)                                          // 如果允许使用移动止损
     {
      PositionsTrailingStop(POSITION_TYPE_BUY,  StartTrailing);   // 买单移动止损
      PositionsTrailingStop(POSITION_TYPE_SELL,  StartTrailing);  // 卖单移动止损
     }
//---
   if(IsLoss(MaxLoss, Magic))
     {
      Comment("出现连续亏损", MaxLoss, "次的单子");
      //--- 如果出现连续亏损,你的代码
     }
   else
     {
      Comment("没有出现连续亏损", MaxLoss, "次的单子");
      //--- 没有出现连续亏损,继续交易的代码
     }
  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
  }
//+------------------------------------------------------------------+
//|  每天限制交易的数量                                             |
//+------------------------------------------------------------------+
bool DailyTradeLimit(int limit)
  {
   int pos_total = 0;                                                              // 初始化单子数量
   HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer());                 // 搜索时间范围,从每天0时开始到当前时间
   int total = HistoryDealsTotal();                                                // 获取时间段内所有单子总数
   if(total > 0)
      for(int i = total - 1; i >= 0; i--)                                          // 历遍所有单子
         if(m_deal.SelectByIndex(i))                                               // 选中单子
            if(m_deal.Symbol() == _Symbol && m_deal.Entry() == DEAL_ENTRY_IN)      // 只选择当前加载图表的货币对名称和入场类型
               pos_total++;
   /*
   判断用户自行输入的参数 limit
   总数若大于或者等于,返回false 表示不能继续交易,否则返回true 表示可以继续交易
   */
   return((pos_total >= limit) ? false : true);
  }
//+------------------------------------------------------------------+
//|  移动止损方法                                                   |
//+------------------------------------------------------------------+
void PositionsTrailingStop(const ENUM_POSITION_TYPE pos_type,
                           const double ts)
  {
   int pos_total = PositionsTotal();                                                     // 取得成交单子总数
   if(pos_total > 0)                                                                     // 如果有单子
      for(int i = 0; i < pos_total; i++)                                                 // 历遍所有单子
         if(m_pos.SelectByIndex(i))                                                      // 选中单子
            if(m_pos.Symbol() == _Symbol && m_pos.PositionType() == pos_type)            // 取当前货币对和单子成交类型
              {
               ulong  pos_ticket = m_pos.Ticket();                                       // 获取单子成交编号
               double pos_open   = m_pos.PriceOpen();                                    // 获取单子成交价格
               double pos_sl     = m_pos.StopLoss();                                     // 获取单子止损价格
               switch(pos_type)                                                          // 分类单子类型
                 {
                  case POSITION_TYPE_BUY:                                                // 如果是买单
                     if(Bid >= pos_open + ts * _Point)                                   // 如果大于设置的移动止损点数
                        if(Bid - ts * _Point > pos_sl)                                   // 如果大于当前止损价
                           if(!m_trade.PositionModify(pos_ticket, Bid - ts * _Point, 0)) // 修改单子新的止损价
                              PrintFormat("%s, %s", __FUNCTION__, "设置买单止损失败!"); // 如果修改失败,打印日志
                     break;                                                              // 退出
                  case POSITION_TYPE_SELL:                                               // 如果是卖单
                     if(Ask <= pos_open - ts * _Point)                                   // 如果小于设置的移动止损点数
                        if(Ask + ts * _Point < pos_sl || pos_sl == 0)                    // 如果小于当前止损价,或者第一次设置止损价
                           if(!m_trade.PositionModify(pos_ticket, Ask + ts * _Point, 0)) // 修改单子新的止损价
                              PrintFormat("%s, %s", __FUNCTION__, "设置卖单止损失败!"); // 如果修改失败,打印日志
                     break;                                                              // 退出
                 }
              }
  }
//+------------------------------------------------------------------+
//|  获取最后成交单平仓时间                                        |
//+------------------------------------------------------------------+
datetime GetHistoryLastDealCloseTime(const ENUM_DEAL_TYPE type)                          // 输入类型
  {
   datetime close_time = 0;                                                              // 初始化平仓时间
   ENUM_DEAL_TYPE deal_type = (type == DEAL_TYPE_BUY) ? DEAL_TYPE_SELL : DEAL_TYPE_BUY;  // 如果输入买单,那么out就是卖类型,反之亦然
   HistorySelect(0, TimeTradeServer());                                                  // 设置搜索时间段, 这里代表所有历史
   int total = HistoryDealsTotal();                                                      // 获取所有数量
   if(total > 0)                                                                         // 如果数量大于0
      for(int i = 0; i < total; i++)                                                     // 历遍所有单子
         if(m_deal.SelectByIndex(i))                                                     // 选中单子
            if(m_deal.Symbol() == _Symbol &&                                             // 只选择当前加载图表的货币对名称
               m_deal.DealType() == deal_type &&                                         // 指定成交类型
               m_deal.Entry() == DEAL_ENTRY_OUT)                                         // 只取出场的成交单
               close_time = m_deal.Time();                                               // 获取平仓时间
   return(close_time);                                                                   // 输出最后平仓时间
  }
//+------------------------------------------------------------------+
//|  判断是否连续亏损                                               |
//+------------------------------------------------------------------+
bool IsLoss(const int count, const long magic = 0)
  {
   HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer());                       // 只统计当天的交易历史
   int total = HistoryDealsTotal();                                                      // 获取当天交易的总单数
   int loss = 0;                                                                         // 初始化连续亏损的次数
   if(total > 0)                                                                         // 如果历史单数大于0
      for(int i = 0; i < total; i++)                                                     // 历遍所有单子
         if(m_deal.SelectByIndex(i))                                                     // 获取单子索引
            if(m_deal.Symbol() == _Symbol &&                                             // 只选当前货币品种
               m_deal.Magic() == magic &&                                                // 如果magic 默认为 0 时视为手动单
               m_deal.Entry() == DEAL_ENTRY_OUT)                                         // 只选平仓属性的成交单
              {
               if(m_deal.Profit() < 0)                                                   // 如果成交单获得小于0,说明是亏损单
                  loss++;                                                                // 连续亏损计数+1
               else
                  loss = 0;                                                              // 若中途有盈利单,重新计数(连续计数初始为0)
               if(loss >= count)                                                         // 若连续亏损大于或者等于自定义计数,返回true值
                  return(true);                                                          // 返回true值
              }
   return(false);
  }
//+------------------------------------------------------------------+
 
Yang Wang #:

呵呵,又遇到你了,

这个逻辑很简单

搜索全部历史,如果是亏损,就让一个计数变量+1,如果出现一次盈利就让这个计数变量清零


首先,非常感谢你,愿意花时间回答问题。

我们应该没有偶遇过吧,我是一个初学者。

你写的代码我要完全看明白可能要花很长的时间,有问题再来请教。

注释真的很有帮助,代码看起来很舒服。 

 
ken138888 #:


首先,非常感谢你,愿意花时间回答问题。

我们应该没有偶遇过吧,我是一个初学者。

你写的代码我要完全看明白可能要花很长的时间,有问题再来请教。

注释真的很有帮助,代码看起来很舒服。 

//+------------------------------------------------------------------+
//|  判断是否连续亏损                                               |
//+------------------------------------------------------------------+
bool IsLoss(const int count, const long magic = 0)
  {
   HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer());                       // 只统计当天的交易历史
   int total = HistoryDealsTotal();                                                      // 获取当天交易的总单数
   int loss = 0;                                                                         // 初始化连续亏损的次数
   if(total > 0)                                                                         // 如果历史单数大于0
      for(int i = 0; i < total; i++)                                                     // 历遍所有单子
         if(m_deal.SelectByIndex(i))                                                     // 获取单子索引
            if(m_deal.Symbol() == _Symbol &&                                             // 只选当前货币品种
               m_deal.Magic() == magic &&                                                // 如果magic 默认为 0 时视为手动单
               m_deal.Entry() == DEAL_ENTRY_OUT)                                         // 只选平仓属性的成交单
              {
               if(m_deal.Profit() < 0)                                                   // 如果成交单获得小于0,说明是亏损单
                  loss++;                                                                // 连续亏损计数+1
               else
                  loss = 0;                                                              // 若中途有盈利单,重新计数(连续计数初始为0)
               if(loss >= count)                                                         // 若连续亏损大于或者等于自定义计数,返回true值
                  return(true);                                                          // 返回true值
              }
   return(false);
  }

这里有点不严谨,例如如果你想在连续亏损3单后中止交易,那么我们就要判断最后3个单子的盈亏情况,如果把黄色部分放在循环体内的话,

在这过程中有超过3单亏损的话,它会直接返回true值,所以不能把这个判断放在循环体内,把它改在到循环体外做判断.

//+------------------------------------------------------------------+
//|  判断是否连续亏损                                               |
//+------------------------------------------------------------------+
bool IsLoss(const int count, const long magic = 0)
  {
   HistorySelect(iTime(_Symbol, PERIOD_D1, 0), TimeTradeServer());                       // 只统计当天的交易历史
   int total = HistoryDealsTotal();                                                      // 获取当天交易的总单数
   int loss = 0;                                                                         // 初始化连续亏损的次数
   if(total > 0)                                                                         // 如果历史单数大于0
      for(int i = 0; i < total; i++)                                                     // 历遍所有单子
         if(m_deal.SelectByIndex(i))                                                     // 获取单子索引
            if(m_deal.Symbol() == _Symbol &&                                             // 只选当前货币品种
               m_deal.Magic() == magic &&                                                // 如果magic 默认为 0 时视为手动单
               m_deal.Entry() == DEAL_ENTRY_OUT)                                         // 只选平仓属性的成交单
              {
               if(m_deal.Profit() < 0)                                                   // 如果成交单获得小于0,说明是亏损单
                  loss++;                                                                // 连续亏损计数+1
               else
                  loss = 0;                                                              // 若中途有盈利单,重新计数(连续计数初始为0)
              }
   return((loss >= count) ? true : false);                                               // 如果在最后为count内有连续超过count次亏损,返回true值
  }
 
Yang Wang #:

这里有点不严谨,例如如果你想在连续亏损3单后中止交易,那么我们就要判断最后3个单子的盈亏情况,如果把黄色部分放在循环体内的话,

在这过程中有超过3单亏损的话,它会直接返回true值,所以不能把这个判断放在循环体内,把它改在到循环体外做判断.

好的,谢谢,原来保本止损都写好了,怪不得说又遇到了,哈哈。

其实我想写一个一次一单的,如果已经平仓的单子如果出现连续亏损,

比如说连续亏损5单后开始加仓,加到把之前连续亏损的5单赚回来就停止加仓。