高手来说说,如何实现平仓后就触发另一个函数?

 

高手来说说,如何实现平仓后就触发另一个函数的执行?

OnTradeTransaction()这函数我用的不太明白

 
universework:

高手来说说,如何实现平仓后就触发另一个函数的执行?

OnTradeTransaction()这函数我用的不太明白

无论平仓,开仓,修改,挂单,OnTradeTransaction()都会被触发,此函数本身就是一个交易事件,和它最象的就是OnTrade()

 
Zhang Yi #:

无论平仓,开仓,修改,挂单,OnTradeTransaction()都会被触发,此函数本身就是一个交易事件,和它最象的就是OnTrade()

是的,问题是如何实现只在平仓行为后触发?如何过滤非平仓行为

 
universework #:

是的,问题是如何实现只在平仓行为后触发?如何过滤非平仓行为

我对这个函数也有不同的地方,但是你这个问题可以这样,不排除还有其他更简洁办法

先用 trans.type 判断事件,找到 TRADE_TRANSACTION_DEAL_ADD 这个事件 属于是在历史中添加了成交单的事件

然后用 trans.deal 作为基准,获取 DEAL_ENTRY 的类型,属于 DEAL_ENTRY_OUT的就是平仓单了

ulong	lastDealID	= trans.deal; 
if(trans.type == TRADE_TRANSACTION_DEAL_ADD)
        {
        if(HistoryDealSelect(lastDealID))       //选中成交单
                {
                ENUM_DEAL_ENTRY entry  = ENUM_DEAL_ENTRY(HistoryDealGetInteger(lastDealID,DEAL_ENTRY));
                if( entry  == DEAL_ENTRY_OUT )
                        {
                        //相关操作
                        }
                }
        }

但是要注意,这个  OnTradeTransaction() 的特殊地方,如果在其他函数中,有对交易操作过多次(例如开仓,挂单,平仓,修改止损止盈),这个 OnTradeTransaction()会在其他操作全部完成后才会进来

换句话说就是,如果Ontick() 里面连续开两单,那么开了两单后才会进入 OnTradeTransaction() 并且会进入2次,并不会开一单进入一次 OnTradeTransaction()

 
Mage He #:

我对这个函数也有不同的地方,但是你这个问题可以这样,不排除还有其他更简洁办法

先用 trans.type 判断事件,找到 TRADE_TRANSACTION_DEAL_ADD 这个事件 属于是在历史中添加了成交单的事件

然后用 trans.deal 作为基准,获取 DEAL_ENTRY 的类型,属于 DEAL_ENTRY_OUT的就是平仓单了

但是要注意,这个  OnTradeTransaction() 的特殊地方,如果在其他函数中,有对交易操作过多次(例如开仓,挂单,平仓,修改止损止盈),这个 OnTradeTransaction()会在其他操作全部完成后才会进来

换句话说就是,如果Ontick() 里面连续开两单,那么开了两单后才会进入 OnTradeTransaction() 并且会进入2次,并不会开一单进入一次 OnTradeTransaction()

很好,试了可以。实际我最终目的是要在检测到出场订单后,要获取这个出场订单对应的in入场订单的comment注释,如何实现?

出场订单的 comment都是空的,所以过滤掉空的,往前遍历就能找到 入场订单的comment注释,但如果同一标的前后入场不同的多个机会, 再往前遍历到入场订单的comment注释就可能与出场订单不是一一对应了,所以如何获取这个出场订单相对应的in入场订单的comment注释?或者如何实现让out出场单子的 comment注释与in 入场订单的 comment注释一致,而不是空?

 
universework #:

很好,试了可以。实际我最终目的是要在检测到出场订单后,要获取这个出场订单对应的in入场订单的comment注释,如何实现?

出场订单的 comment都是空的,所以过滤掉空的,往前遍历就能找到 入场订单的comment注释,但如果同一标的前后入场不同的多个机会, 再往前遍历到入场订单的comment注释就可能与出场订单不是一一对应了,所以如何获取这个出场订单相对应的in入场订单的comment注释?或者如何实现让out出场单子的 comment注释与in 入场订单的 comment注释一致,而不是空?

可能你们把问题想复杂了,如果你只是单纯的想获取out(平仓)类型单子和它对应in(开仓)类型单子的注释, 那么这个就比较简单,无需用到 OnTradeTransaction() 或者  OnTrade()函数了。

首先,你先要知道你将要平仓的执仓订单编号,进行平仓操作(具体如何获取,这里就不详细说明了,我相信方法你应该会)

不喜勿喷^_^

a

//+------------------------------------------------------------------+
//|                                                        Test1.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
CTrade        m_trade;
CDealInfo     m_deal;
CSymbolInfo   m_symbol;
CPositionInfo m_pos;
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   if(!m_symbol.Name(_Symbol)) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(m_symbol.Name());
   m_trade.SetDeviationInPoints(INT_MAX);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA报价函数                                                       |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- protection against the return value of "zero"
   if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| 平仓并获取对应in入场的单子的注释                              |
//+------------------------------------------------------------------+
string ClosePosition(const long ticket, const long magic)
  {
   if(!m_pos.SelectByTicket(ticket))                // 如果单子不存在,返回空字符串
      return(NULL);
   datetime open_time  = m_pos.Time();              // 将被平仓单子的入场时间
   m_trade.SetExpertMagicNumber(magic);             // 设置被平仓单子的魔术编号
   if(m_trade.PositionClose(ticket))                // 执行平仓
     {
      HistorySelect(open_time, TimeTradeServer());  // 从被平仓单子的入场时间开始搜索
      int total = HistoryDealsTotal();              // 获取历史成交总数
      for(int i = 0; i < total; i++)                // 按顺序搜索历史
        {
         if(!m_deal.SelectByIndex(i))               // 如果选中失败,继续
            continue;
         if(m_deal.Symbol() != m_symbol.Name())     // 如果是当前货币名称,继续
            continue;
         if(m_deal.Entry() != DEAL_ENTRY_IN)        // 如果是in类型单子,继续
            continue;
         if(m_deal.Order() != ticket)               // 如果订单编号匹配,继续
            continue;
         return(m_deal.Comment());                  // 返回注释并退出搜索
        }
     }
   return(NULL);                                    // 平仓失败,返回空字符串
  }
//+------------------------------------------------------------------+
 
Zhang Yi #:

可能你把问题想复杂了,如果你只是单纯的想获取out(平仓)类型单子和它对应in(开仓)类型单子的注释, 那么这个就比较简单,无需用到 OnTradeTransaction() 或者  OnTrade()函数了。

首先,你先要知道你将要平仓的订单编号,进行平仓操作(具体如何获取,这里就不详细说明了,我相信方法你应该会)

不喜勿喷^_^



//+------------------------------------------------------------------+
//|                                                      ProjectName |
//|                                      Copyright 2020, CompanyName |
//|                                       http://www.companyname.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
CTrade        m_trade;
CDealInfo     m_deal;
CSymbolInfo   m_symbol;
CPositionInfo m_pos;
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   if(!m_symbol.Name(_Symbol)) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(m_symbol.Name());
   m_trade.SetDeviationInPoints(INT_MAX);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {
   if(HistorySelect(0,TimeCurrent()))
     {
      int ht=HistoryDealsTotal();
      for(int j=ht-1; j>=0; j--)
        {
         if(HistoryDealGetTicket(j)>0 && HistoryDealGetString(HistoryDealGetTicket(j),DEAL_SYMBOL)==Symbol())
           {
            string com= ClosePosition(HistoryDealGetTicket(j),NULL);
            Print(com);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- protection against the return value of "zero"
   if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| 平仓并获取对应in入场的单子的注释                              |
//+------------------------------------------------------------------+
string ClosePosition(const long ticket, const long magic)
  {
   if(!m_pos.SelectByTicket(ticket))                // 如果单子不存在,返回空字符串
      return(NULL);
   datetime open_time  = m_pos.Time();              // 将被平仓单子的入场时间
   m_trade.SetExpertMagicNumber(magic);             // 设置被平仓单子的魔术编号
   if(m_trade.PositionClose(ticket))                // 执行平仓
     {
      HistorySelect(open_time, TimeTradeServer());  // 从被平仓单子的入场时间开始搜索
      int total = HistoryDealsTotal();              // 获取历史成交总数
      for(int i = 0; i < total; i++)                // 按顺序搜索历史
        {
         if(!m_deal.SelectByIndex(i))               // 如果选中失败,继续
            continue;
         if(m_deal.Symbol() != m_symbol.Name())     // 如果是当前货币名称,继续
            continue;
         if(m_deal.Entry() != DEAL_ENTRY_IN)        // 如果是in类型单子,继续
            continue;
         if(m_deal.Order() != ticket)               // 如果订单编号匹配,继续
            continue;
         return(m_deal.Comment());                  // 返回注释并退出搜索
        }
     }
   return(NULL);                                    // 平仓失败,返回空字符串
  }
//+------------------------------------------------------------------+
以上手动平了一个带comment注释的单子,但没有把comment获取打印出来,问题出在哪?
 
以上手动平了一个带comment注释的单子,但没有把comment获取打印出来,问题出在哪?
 
universework #:
以上手动平了一个带comment注释的单子,但没有把comment获取打印出来,问题出在哪?

你搞错了,这里的 ticket 指的是正在交易中执仓的订单编号(即你想要平仓的订单编号,具体如何在EA中用代码获取,我就不写了)

string ClosePosition(const long ticket, const long magic)

例如,我想平仓订单编号为 15338917的单子

a

void OnTick()
  {
//---
   Print(ClosePosition(15338917, 0));
  }

这样可以获取和它对应in的注释

b

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

如果你的目的是手动平仓,那么此时我们就需要用到这个系统函数了,即交易事件发生时

void OnTrade(void)

具体方法代码如下:

//+------------------------------------------------------------------+
//|                                                        Test1.mq5 |
//|                                  Copyright 2023, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
CTrade        m_trade;
CDealInfo     m_deal;
CSymbolInfo   m_symbol;
CPositionInfo m_pos;
//+------------------------------------------------------------------+
//| EA交易初始化函数                                                |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   if(!m_symbol.Name(_Symbol)) // sets symbol name
      return(INIT_FAILED);
   RefreshRates();
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(m_symbol.Name());
   m_trade.SetDeviationInPoints(INT_MAX);
   IsLastOutTicket(); // 初始化检查一次
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA报价函数                                                       |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTrade(void)
  {
//---
   long pos_id = IsLastOutTicket();
   if(pos_id > 0)
     {
      HistorySelect(0, TimeTradeServer());
      int total_deal = HistoryDealsTotal();
      for(int i = total_deal - 1; i >= 0; i--)
         if(m_deal.SelectByIndex(i))
            if(m_deal.Entry() == DEAL_ENTRY_IN)
               if(m_deal.Order() == pos_id)
                 {
                  printf("有新的平仓交易, 它的入场注释 = %s", m_deal.Comment());
                  break;
                 }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- protection against the return value of "zero"
   if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| 在历史中检查新平仓的交易,如果有返回它的订单ID                 |
//+------------------------------------------------------------------+
long IsLastOutTicket(void)
  {
   static datetime last_deal_time = 0;
   static long     last_position_id = 0;
   if(!::HistorySelect(last_deal_time, UINT_MAX)) // 如果没有得到历史,就退出
      return(WRONG_VALUE);
   int total_deals = ::HistoryDealsTotal();       // 在取得的列表中得到交易的数量
   for(int i = total_deals - 1; i >= 0; i--)      // 遍历在获得的列表中的全部交易,从最新的到最开始的
     {
      if(!m_deal.SelectByIndex(i))                // 取得交易编号
         continue;
      if(m_deal.Symbol() != m_symbol.Name())      // 如果货币名称匹配,继续
         continue;
      if(m_deal.PositionId() == last_position_id) // 如果订单ID匹配,就退出
         return(WRONG_VALUE);
      else                                        // 如果单号没有匹配,就进行通知
         if(m_deal.Entry() == DEAL_ENTRY_OUT)     // 记住最新平仓交易的时间和订单ID
           {
            last_deal_time   = m_deal.Time();
            last_position_id = m_deal.PositionId();
            return(last_position_id);
           }
     }
   return(WRONG_VALUE);                           
  }
这些都是很简单的方式方法,没必要搞复杂了。如果你看不懂我也没办法,我的目的不是教人,我只是帮忙你解决问题,不喜勿喷。。。
 
Zhang Yi #:

你搞错了,这里的 ticket 指的是正在交易中执仓的订单编号(即你想要平仓的订单编号,具体如何在EA中用代码获取,我就不写了)

例如,我想平仓订单编号为 15338917的单子

这样可以获取和它对应in的注释

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

如果你的目的是手动平仓,那么此时我们就需要用到这个系统函数了,即交易事件发生时

具体方法代码如下:

这些都是很简单的方式方法,没必要搞复杂了。如果你看不懂我也没办法,我的目的不是教人,我只是帮忙你解决问题,不喜勿喷。。。

棒棒哒

 

MT提供的消息 只是一般的交易活动,且优先级不高,大致和计时消息相当,即不是一个消息产生必须响应处理完 才发下各消息, 即发生消息和处理响应消息是异步的、不同步、不必然有序。


因此如果你需要通过comment分析单子之间的关系,应自己 保留 、查找、管理有关关系信息。当然这对编程能力要求较高

参考 https://www.mql5.com/zh/articles/88

用于在以仓位为中心的 MetaTrader 5 环境中跟踪订单的虚拟订单管理程序
用于在以仓位为中心的 MetaTrader 5 环境中跟踪订单的虚拟订单管理程序
  • www.mql5.com
可以将此类库添加到 MetaTrader 5 EA 交易程序,从而能够通过一种与 MetaTrader 4 非常类似的以订单为中心的方法编写程序(与基于仓位的 MetaTrader 5 相比较)。它通过在 MetaTrader 5 客户端跟踪虚拟订单,同时为每个仓位维护一个保护性经纪人止损,从而提供灾难防护来实现这一目的。