記事「自動で動くEAを作る(第08回):OnTradeTransaction」についてのディスカッション

 

新しい記事「自動で動くEAを作る(第08回):OnTradeTransaction」はパブリッシュされました:

今回は、受注システムに関する問題を迅速かつ効率的に処理するためのイベント処理システムの使用方法について紹介します。このシステムにより、EAは必要なデータを常に検索する必要がなくなり、より速く動作するようになります。

これで、だいぶ完成度が上がり、ようやくC_ManagerクラスとEAの相性がよくなってきました。どちらも効果があり、攻撃的になったり、非友好的になったりしないように気を配ることができます。このように、EAとC_Managerクラス間のメッセージフローは、図02のようになります。

図02

図02:新しい関数によるメッセージフロー


このフローは複雑すぎる、あるいはまったく機能していないと思われるかもしれませんが、まさにこれまで実装されてきたものなのです。

図02を見ると、EAのコードが非常に複雑だと思われるかもしれませんが、多くの人がEAに必要なコードと考えるものよりも、はるかにシンプルなものです。特に自動化されたEAとなるとそうです。次のことを忘れないでください。EAが実際に取引を発生させることはありません。EAは取引サーバと通信するための手段やツールに過ぎません。つまり、実際にはトリガーがかかると反応するだけなのです。

作者: Daniel Jose

 

このような素晴らしい記事をありがとうございます。

このような素晴らしい記事を書いていただきありがとうございます。 ポジションをオープンするコードを書いたのですが、デモ口座で実行すると正しい値を返すのですが、リアル口座で実行すると0を返します。

デモ口座で実行すると正しい値を返しますが、リアル口座で実行すると0を返します。

私の目的は、ポジションを建てた後にその取引チケットを返すことです。
//+------------------------------------------------------------------+
//|  &nbspテスト1.mq5
//|  Copyright 2023, MetaQuotes Ltd.|メタクォーツ株式会社
//|&|||&nbsph ttps:// www.mql5.com
//+------------------------------------------------------------------+
#property copyright "Copyright 2018, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>
CTrade    m_trade;
CDealInfo m_deal;
//+------------------------------------------------------------------+
//| EAトレード初期化関数|EAトレード初期機能; |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   OpenPosition(ORDER_TYPE_BUY, 0.01, 123456);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA クォーテーション機能|||EA; ||
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
ulong OpenPosition(const ENUM_ORDER_TYPE type,
                   const double lot,
                   const long magic)
  {
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   m_trade.SetExpertMagicNumber(magic);
   if(m_trade.PositionOpen(_Symbol, type, lot, (type == ORDER_TYPE_BUY) ? ask : bid, 0, 0))
     {
      ulong deal_ticket = m_trade.ResultDeal();
      if(HistoryDealSelect(deal_ticket))
         m_deal.Ticket(deal_ticket);
      string flag = (m_deal.DealType() == DEAL_TYPE_BUY) ? "buy" : "sell";
      printf(StringFormat("open deal ticket= #%%d order ticket= #%%d %%s %%.2f %%s at %%.%df", _Digits),
             deal_ticket, m_deal.Order(), flag, m_deal.Volume(), _Symbol, m_deal.Price());
      return(deal_ticket);
     }
   return(0);
  }


 
Yang Wang #:

オラ、ダニエル・ホセ

とても素晴らしい記事をありがとうございます。 今、困っていることがあるのですが、あるポジションを選択するためのコードを作成しました。

デモ版で実行された場合、数値は0に戻りますが、実際の版で実行された場合、数値は0に戻ります。問題は何ですか?




.

をクリックしてください。

ulong OpenPosition( const ENUM_ORDER_TYPE type,
                   const double lot,
                   const long magic)
  {
   double ask = SymbolInfoDouble ( _Symbol , SYMBOL_ASK );
   double bid = SymbolInfoDouble ( _Symbol , SYMBOL_BID );
   m_trade.SetExpertMagicNumber(magic);
   if (m_trade.PositionOpen( _Symbol , type, lot, (type == ORDER_TYPE_BUY ) ? ask : bid, 0 , 0 ))
     {
       ulong deal_ticket = m_trade.ResultDeal();
       if ( HistoryDealSelect (deal_ticket))
         m_deal.Ticket(deal_ticket);
       string flag = (m_deal.DealType() == DEAL_TYPE_BUY ) ? "buy" : "sell" ;
       printf ( StringFormat ( "open deal ticket= #%%d order ticket= #%%d %%s %%.2f %%s at %%.%df" , _Digits ),
             deal_ticket, m_deal.Order(), flag, m_deal.Volume(), _Symbol , m_deal.Price());
       return (deal_ticket);
     }
   Print("Error: ", m_trade.ResultRetcode());
   return ( 0 );
  }
 
Daniel Jose #:

その際、"returnado "されているエラーを確認し、"destacada "のロゴを追加すること。

いいえ、私の目的はディールチケットを 返すことです。

デモ口座ではポジションのディールチケットを返すことができますが、リアル口座ではゼロ値を返します。

ulong OpenPosition(const ENUM_ORDER_TYPE type,
                   const double lot,
                   const long magic)
  {
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   m_trade.SetExpertMagicNumber(magic);
   if(m_trade.PositionOpen(_Symbol, type, lot, (type == ORDER_TYPE_BUY) ? ask : bid, 0, 0))
      return(m_trade.ResultDeal());
   return(0);
  }
 
Yang Wang #:

いや、私の目的は、 合意して 2億ドルを獲得 することだ。

デモ・アカウントではポジションの営業チケットは取り戻せますが、リアル・アカウントではゼロになります。

を追加するように指示した行は 、NO É... を繰り返してください。 NO É para retornar nenhum valor ... それは 、ポジションを獲得するためにしている エラーを確認するためのものです... 戻された値を使用する必要はありません... エラータブでエラーを確認する... ドキュメントを見る

 

こんにちは、この連載を拝見しています。尊敬しています。本当に参考になります。

注文を作成した後、その注文を削除しました。しかし、EAはもう新しい注文を作成することができません。

このコードスニペット:

 case TRADE_TRANSACTION_ORDER_DELETE :
                         if (trans.order == trans.position) (*manager).PendingToPosition();
                         else (*manager).UpdatePosition(trans.position); // ORDER?
                         break ;

trans.positionを使用していますが、注文を削除した場合は常に0になります。その最初の条件はreturn文に直接それを送ります。

trans.orderチケットを渡そうとしましたが、m_positionのデータが0なので、チケットは0(! = m_Position.Ticket)なので、コードは無視します:

この後新規注文を作成しようとすると、m_ticketPendingに最初の注文の値があるので、作成されない。

EraseTicketPendingが呼ばれないのは、TRADE_ACTION_REMOVEが 到着すると、request.request.TRADE_ACTION_REMOVEが 常にfalseなので、この条件が常にfalseになるから。

 if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && (request.magic == def_MAGIC_NUMBER))

request.magicは0なので、常にfalseです。

次の章で修正されるかどうか調査します。

よろしくお願いします。

 

問題を見つけました。

MT5のユーザーインターフェイスから 注文を削除する場合、マジックナンバーは0です。

 if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && ((request.magic == def_MAGIC_NUMBER) || request.magic == 0 ))

に変更したところ、期待通りに動作しているようです。

ファイル:
 
Yang Wang #:

こんにちは、ダニエル・ホセ。

ポジションをオープンするコードを書いたのですが、デモ口座で実行すると正しい値を返すのですが、リアル口座で実行すると0を返します。

デモ口座で実行すると正しい値を返しますが、リアル口座で実行すると0を返します。

私の目的は、ポジションを建てた後にその取引チケットを返すことです。


この関数はポジションをオープンし、ディールチケットを返します:

//+------------------------------------------------------------------+
//|&nbsp; &nbspテスト1.mq5
//|&nbsp; Copyright 2023, MetaQuotes Ltd.|メタクォーツ株式会社
//|&|||&nbsph ttps:// 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;
input double TakeProfit = 0;
input double StopLoss   = 0;
input string PositionComment = "";
double m_point;
//+------------------------------------------------------------------+
//| EAトレード初期化関数|EAトレード初期機能; |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   if(!m_symbol.Name(_Symbol)) // シンボル名を設定する
      return(INIT_FAILED);
   RefreshRates();
   m_trade.SetMarginMode();
   m_trade.SetTypeFillingBySymbol(m_symbol.Name());
   m_trade.SetDeviationInPoints(INT_MAX);
   int adjust = (m_symbol.Digits() == 3 || m_symbol.Digits() == 5) ? 10 : 1;
   m_point = m_symbol.Point() * adjust;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA クォーテーション機能|||EA; ||
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- リフレッシュ・レート
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- "ゼロ "の戻り値からの保護
   if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|&nbsp; &nbspnbsp; &nbsp; &nbspnbsp; &nbsp; &nbsp
//+------------------------------------------------------------------+
ulong OpenPosition(const ENUM_ORDER_TYPE type,
                   const double volume,
                   const long magic)
  {
   ulong deal_ticket = 0;
   double sl = 0;
   double tp = 0;
   m_trade.SetExpertMagicNumber(magic);
   RefreshRates();
   double ask = m_symbol.Ask();
   double bid = m_symbol.Bid();
   switch(type)
     {
      case ORDER_TYPE_BUY:
         if(TakeProfit > 0)
            tp = m_symbol.NormalizePrice(ask + TakeProfit * m_point);
         if(StopLoss > 0)
            sl = m_symbol.NormalizePrice(bid - StopLoss * m_point);
         break;
      case ORDER_TYPE_SELL:
         if(TakeProfit > 0)
            tp = m_symbol.NormalizePrice(bid - TakeProfit * m_point);
         if(StopLoss > 0)
            sl = m_symbol.NormalizePrice(ask + StopLoss * m_point);
         break;
     }
   static datetime from_date = iTime(m_symbol.Name(), PERIOD_D1, 0);
   ulong time = GetTickCount64();
   if(m_trade.PositionOpen(m_symbol.Name(), type, volume, (type == ORDER_TYPE_BUY) ? ask : bid, sl, tp, PositionComment))
     {
      ulong open_execution = GetTickCount64() - time;
      do
        {
         ulong order_ticket = m_trade.ResultOrder();
         HistorySelect(from_date, TimeTradeServer());
         int total = HistoryDealsTotal();
         for(int i = total - 1; i >= 0; i--)
           {
            if(!m_deal.SelectByIndex(i))
               continue;
            if(m_deal.Symbol() != m_symbol.Name())
               continue;
            if(m_deal.Entry() != DEAL_ENTRY_IN)
               continue;
            if(m_deal.Order() != order_ticket)
               continue;
            printf(StringFormat("open  #%%I64u %%s %%.2f %%s at %%.%df done in %%I64u ms", m_symbol.Digits()),
                   m_deal.Order(), (type == ORDER_TYPE_BUY) ? "buy" : "sell", m_deal.Volume(), m_deal.Symbol(), m_deal.Price(), open_execution);
            from_date = m_deal.Time();
            deal_ticket = m_deal.Ticket();
            break;
           }
        }
      while(deal_ticket == 0);
     }
   return(deal_ticket);
  }
//+------------------------------------------------------------------+
 
OnTradeTransaction は素晴らしいのですが、本当に問題があります。
MT4 で以前やっていたように、イベント(ポジションのオープン、クローズ、変更)をキャッチするために使い始めました(何が起こったかを推測するためにポジションを常にチェックする)。
しかし、EAが1時間の間にダウンまたはオフした場合はどうなりますか:もちろんイベントは受信しませんが、再起動すると1時間の間に混乱したイベントを取得できません。そのため、何が起こったかを推測するためには、ポジションを分析することによって古いMT4の方法を実行する必要があります。この問題を解決するには、イベントを検出する2つの方法(MT5の方法とバックアップとしてのMT4の方法)を維持しなければなりません。
 
OnTradeTransaction が未決注文のイベント(変更と削除)を検出するのに最大 5 秒かかります。これは正常ですか?
成行ポジションの場合は即時です。
 
Gad Benisty OnTradeTransactionは 素晴らしいのですが、本当に問題があります。以前MT4でやっていたように、イベント(ポジションのオープン、クローズ、変更)をキャッチするために使い始めました(何が起こったかを推測するために常にポジションをチェックする)。その面では、MT5のアプローチは非常にクリーンです。しかし、EAが1時間の間にダウンまたはオフした場合はどうなりますか:もちろん、EAはイベントを受信しませんが、再起動すると、1時間の間に混乱したイベントを取得できません。そのため、何が起こったかを推測するためには、ポジションを分析することによって古いMT4の方法を実行する必要があります。この問題を解決するには、イベントを検出する2つの方法(MT5の方法とバックアップとしてのMT4の方法)を維持しなければなりません。

そうですね...だからExpert Advisorの起動時にポジションや未決注文のチェックが行われるのですね。しかし、これはこの同じシーケンスの少し先の記事に記載されています。

モデレーターによる自動翻訳