MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第21部): 取引クラス - 基本クロスプラットフォーム取引オブジェクト

24 1月 2020, 14:09
Artyom Trishkin
0
277

内容

この記事では、取引クラスという、新しい幅広いトピックを開始します。

概念

いつでもデータに簡単にアクセスできるというのはよいことですが、取引に適用できないとすれば、そのデータは役に立ちません。これは、既存の機能とともに取引機能が必要であることを意味します。
このセクションではすべてを段階的に行うので、セクションは比較的大きくなります。

  • MetaTrader 5とMetaTrader 4の違いに関係なく、これらのプラットフォームの両方から取引リクエストを送ることができるべきです。統一が必要です。
  • まず、意図的に誤ったリクエストでサーバが負荷されないように、取引リクエストを検証する必要があります。
  • 取引サーバのリターンコードを考慮して正しく処理します。サーバにリクエストを送信するときに、EAはサーバとの「リクエスト/レスポンス」対話を維持します。ここでのタスクは、そのような「通信チャネル」、すなわち取引サーバーの応答を処理するメソッドを作成することです。
  • 「できる限りコストを抑えて」ポジションを開く必要がある場合があるため、サーバの応答を処理するいくつかのオプションを作成する必要があります。これを行うには、注文が拒否された場合にサーバにリクエストを繰り返し送信するように手配する必要があります。取引リクエストのパラメータを調整するかリクエストを再送信するか、すべてのパラメータをそのままにして、これらのパラメータを持つリクエストが渡されるとすぐに送信されるような適切な瞬間を待機することができます。また、意図的に悪い価格で注文を再送信しないように、価格レベルを考慮する必要があります。
    場合によっては、リクエストの結果に関係なく取引リクエストを送信し、作業を継続する必要があります。
  • また、ライブラリベースのプログラムをMQL5マーケットに配置する際には、問題を回避するために、取引クラスの動作を調整する必要があります。このようなプログラムはすべてのチェックに合格するべきです。

以上が、取引クラスに関する現在の計画です。
この記事では、基本取引オブジェクトの開発について検討します。これは、プラットフォームに関係なく同じ方法でサーバに取引リクエストを送信するクラスです。サーバにリクエストを送信する場合、このような取引オブジェクトにより、検証済みの正しい取引リクエストパラメータがサーバに渡されます。パラメータはこのオブジェクトでは検証されず、代わりに、後に開発される基本取引クラスで検証されます。
チケットによる注文またはポジションの選択は、現時点では現在の取引オブジェクトに実装されていますが、基本取引クラスを作成した後にはそのクラスに再配置されます。

取引全体が銘柄に直接結び付けられているため、基本取引オブジェクトは、第14部で検討した銘柄オブジェクトの一部になります。銘柄取引オブジェクトへのアクセスは、後に基本取引クラスで手配されます。この記事では、第3部で検討したCEngineライブラリ基本クラスから銘柄取引オブジェクトへの一時的なアクセスを手配します。これは、すべての環境データが蓄積されるクラスで、取引クラスを操作するために必要なすべての口座プロパティと銘柄プロパティを備えています。

基本取引オブジェクトの作成

取引クラスの作業を記録するには、Defines.mqhライブラリファイルにログレベルの列挙を作成する必要があります。
Defines.mqhの最後に必要な列挙を追加します。

//+------------------------------------------------------------------+
//| Data for working with trading classes                            |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|  Logging level                                                   |
//+------------------------------------------------------------------+
enum ENUM_LOG_LEVEL
  {
   LOG_LEVEL_NO_MSG,                                        // Trading logging disabled
   LOG_LEVEL_ERROR_MSG,                                     // Only trading errors
   LOG_LEVEL_ALL_MSG                                        // Full logging
  };
//+------------------------------------------------------------------+


操作ログにメッセージを表示するには、ライブラリメッセージのリストにメッセージテキストとそのインデックスが必要です。
Datas.mqhファイルに必要なインデックスを追加します

   MSG_LIB_SYS_NOT_SYMBOL_ON_SERVER,                  // Error. No such symbol on server
   MSG_LIB_SYS_NOT_SYMBOL_ON_LIST,                    // Error. No such symbol in the list of used symbols: 
   MSG_LIB_SYS_FAILED_PUT_SYMBOL,                     // Failed to place to market watch. Error: 
   MSG_LIB_SYS_ERROR_NOT_POSITION,                    // Error. Not a position:
   MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET,    // Error. No open position with ticket #
   MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET,     // Error. No placed order with ticket #
   MSG_LIB_SYS_ERROR_FAILED_CLOSE_POS,                // Failed to closed position. Error 
   MSG_LIB_SYS_ERROR_FAILED_MODIFY_ORD,               // Failed to modify order. Error
   MSG_LIB_SYS_ERROR_UNABLE_PLACE_WITHOUT_TIME_SPEC,  // Error: Cannot place order without explicitly specified expiration time
   MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ,            // Error. Failed to get trading object
   MSG_LIB_SYS_ERROR_FAILED_GET_POS_OBJ,              // Error. Failed to get position object
   MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ,              // Error. Failed to get order object
   MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ,              // Error. Failed to get symbol object
   MSG_LIB_SYS_ERROR_CODE_OUT_OF_RANGE,               // Return code out of range of error codes
   MSG_LIB_TEXT_FAILED_ADD_TO_LIST,                   // failed to add to list
   MSG_LIB_TEXT_TIME_UNTIL_THE_END_DAY,               // Order lifetime till the end of the current day to be used
   MSG_LIB_TEXT_SUNDAY,                               // Sunday
   MSG_ACC_MARGIN_MODE_RETAIL_EXCHANGE,               // Exchange markets mode
   MSG_ACC_UNABLE_CLOSE_BY,                           // Close by is available only on hedging accounts
   MSG_ACC_SAME_TYPE_CLOSE_BY,                        // Error. Positions for close by are of the same type
   
//--- CEngine
   MSG_ENG_NO_TRADE_EVENTS,                           // There have been no trade events since the last launch of EA
   MSG_ENG_FAILED_GET_LAST_TRADE_EVENT_DESCR,         // Failed to get description of the last trading event
   MSG_ENG_FAILED_GET_MARKET_POS_LIST,                // Failed to get the list of open positions
   MSG_ENG_FAILED_GET_PENDING_ORD_LIST,               // Failed to get the list of placed orders
   MSG_ENG_NO_OPEN_POSITIONS,                         // No open positions
   MSG_ENG_NO_PLACED_ORDERS,                          // No placed orders

  };

ここには、「geolocation」(インデックス列挙定数を追加する必要がある)を持つファイルの部分のみが表示されています。

次に、インデックスを定義したばかりの必要なメッセージをテキストメッセージの配列に追加します

   {"Ошибка. Такого символа нет на сервере","Error. No such symbol on server"},
   {"Ошибка. Такого символа нет в списке используемых символов: ","Error. This symbol is not in the list of symbols used: "},
   {"Не удалось поместить в обзор рынка. Ошибка: ","Failed to put in market watch. Error: "},
   {"Ошибка. Не позиция: ","Error. Not position: "},
   {"Ошибка. Нет открытой позиции с тикетом #","Error. No open position with ticket #"},
   {"Ошибка. Нет установленного ордера с тикетом #","Error. No placed order with ticket #"},
   {"Не удалось закрыть позицию. Ошибка ","Could not close position. Error "},
   {"Не удалось модифицировать ордер. Ошибка ","Failed to modify order. Error "},
   {"Ошибка: невозможно разместить ордер без явно заданного его времени истечения","Error: Unable to place order without explicitly specified expiration time"},
   {"Ошибка. Не удалось получить торговый объект","Error. Failed to get trade object"},
   {"Ошибка. Не удалось получить объект-позицию","Error. Failed to get position object"},
   {"Ошибка. Не удалось получить объект-ордер","Error. Failed to get order object"},
   {"Ошибка. Не удалось получить объект-символ","Error. Failed to get symbol object"},
   {"Код возврата вне заданного диапазона кодов ошибок","Return code out of range of error codes"},
   {"не удалось добавить в список","failed to add to list"},
   {"Будет использоваться время действия ордера до конца текущего дня","Order validity time until the end of the current day will be used"},
   
   {"Воскресение","Sunday"},
   {"Биржевой рынок","Exchange market mode"},
   {"Закрытие встречным доступно только на счетах с типом \"Хеджинг\"","Close by opposite position iavailable only on \"Hedging\" accounts"},
   {"Ошибка. Позиции для встречного закрытия имеют один и тот же тип","Error. Positions of the same type in counterclosure request"},
   
//--- CEngine
   {"С момента последнего запуска ЕА торговых событий не было","No trade events since the last launch of EA"},
   {"Не удалось получить описание последнего торгового события","Failed to get description of the last trading event"},
   {"Не удалось получить список открытых позиций","Failed to get open positions list"},
   {"Не удалось получить список установленных ордеров","Failed to get pending orders list"},
   {"Нет открытых позиций","No open positions"},
   {"Нет установленных ордеров","No placed orders"},

  };

インデックス定数の定義と同様に、必要なメッセージテキストを追加するための特定の領域のみがここに表示されます。添付ファイルには改善されたDatas.mqhが完全に含まれているので分析に使用できます。

ポジション決済リクエストを送信する場合、ポジション決済の方向と反対の注文のタイプを知る必要があります(MQL5では、反対のポジションを開くことによって決済が実行されますが、取引リクエストに送信されるのは注文(ポジションではない)タイプです )。
DELib.mqhライブラリのサービス関数ファイルで、ポジションの方向によって注文タイプを受け取る関数ポジションの方向と反対の注文のタイプを受け取る関数の2つを書きます。

//+------------------------------------------------------------------+
//| Return an order type by a position type                          |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE OrderTypeByPositionType(ENUM_POSITION_TYPE type_position)
  {
   return(type_position==POSITION_TYPE_BUY ? ORDER_TYPE_BUY :  ORDER_TYPE_SELL);
  }
//+------------------------------------------------------------------+
//| Return a reverse order type by a position type                   |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE OrderTypeOppositeByPositionType(ENUM_POSITION_TYPE type_position)
  {
   return(type_position==POSITION_TYPE_BUY ? ORDER_TYPE_SELL :  ORDER_TYPE_BUY);
  }
//+------------------------------------------------------------------+


すべてのデータを準備したので、取引オブジェクトクラス自体に取り組みましょう。

\MQL5\Include\DoEasy\Objects\Trade\サブフォルダとを作成し、その中で、新しいCTradeObj クラスをTradeObj.mqhファイルに作成します。
サービス関数のファイルを新しく作成されたファイルにインクルードします

//+------------------------------------------------------------------+
//|                                                     TradeObj.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+


必要なすべてのクラスメンバ変数とメソッドをクラスファイルに追加します。

//+------------------------------------------------------------------+
//|                                                     TradeObj.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\DELib.mqh"
//+------------------------------------------------------------------+
//| Trading object class                                             |
//+------------------------------------------------------------------+
class CTradeObj
  {
private:
   MqlTick                    m_tick;                                            // Tick structure for receiving prices
   MqlTradeRequest            m_request;                                         // Trade request structure
   MqlTradeResult             m_result;                                          // trade request execution result
   ENUM_ACCOUNT_MARGIN_MODE   m_margin_mode;                                     // Margin calculation mode
   ENUM_ORDER_TYPE_FILLING    m_type_filling;                                    // Filling policy
   ENUM_ORDER_TYPE_TIME       m_type_expiration;                                 // Order expiration type
   int                        m_symbol_expiration_flags;                         // Flags of order expiration modes for a trading object symbol
   ulong                      m_magic;                                           // Magic number
   string                     m_symbol;                                          // Symbol
   string                     m_comment;                                         // Comment
   ulong                      m_deviation;                                       // Slippage in points
   double                     m_volume;                                          // Volume
   datetime                   m_expiration;                                      // Order expiration time (for ORDER_TIME_SPECIFIED type order)
   bool                       m_async_mode;                                      // Flag of asynchronous sending of a trade request
   ENUM_LOG_LEVEL             m_log_level;                                       // Logging level
   int                        m_stop_limit;                                      // Distance of placing a StopLimit order in points
public:
//--- コンストラクタ
                              CTradeObj();;

//--- Set default values
   void                       Init(const string symbol,
                                   const ulong magic,
                                   const double volume,
                                   const ulong deviation,
                                   const int stoplimit,
                                   const datetime expiration,
                                   const bool async_mode,
                                   const ENUM_ORDER_TYPE_FILLING type_filling,
                                   const ENUM_ORDER_TYPE_TIME type_expiration,
                                   ENUM_LOG_LEVEL log_level);
                                   
//--- (1) Return the margin calculation mode, (2) hedge account flag
   ENUM_ACCOUNT_MARGIN_MODE   GetMarginMode(void)                                const { return this.m_margin_mode;           }
   bool                       IsHedge(void) const { return this.GetMarginMode()==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING;          }
//--- (1) Set, (2) return the error logging level
   void                       SetLogLevel(const ENUM_LOG_LEVEL level)                  { this.m_log_level=level;              }
   ENUM_LOG_LEVEL             GetLogLevel(void)                                  const { return this.m_log_level;             }
//--- (1) Set, (2) return the filling policy
   void                       SetTypeFilling(const ENUM_ORDER_TYPE_FILLING type)       { this.m_type_filling=type;            }
   ENUM_ORDER_TYPE_FILLING    GetTypeFilling(void)                               const { return this.m_type_filling;          }
//--- (1) Set, (2) return order expiration type
   void                       SetTypeExpiration(const ENUM_ORDER_TYPE_TIME type)       { this.m_type_expiration=type;         }
   ENUM_ORDER_TYPE_TIME       GetTypeExpiration(void)                            const { return this.m_type_expiration;       }
//--- (1) Set, (2) return the magic number
   void                       SetMagic(const ulong magic)                              { this.m_magic=magic;                  }
   ulong                      GetMagic(void)                                     const { return this.m_magic;                 }
//--- (1) Set, (2) return a symbol
   void                       SetSymbol(const string symbol)                           { this.m_symbol=symbol;                }
   string                     GetSymbol(void)                                    const { return this.m_symbol;                }
//--- (1) Set, (2) return a comment
   void                       SetComment(const string comment)                         { this.m_comment=comment;              }
   string                     GetComment(void)                                   const { return this.m_comment;               }
//--- (1) Set, (2) return slippage
   void                       SetDeviation(const ulong deviation)                      { this.m_deviation=deviation;          }
   ulong                      GetDeviation(void)                                 const { return this.m_deviation;             }
//--- (1) Set, (2) return volume
   void                       SetVolume(const double volume)                           { this.m_volume=volume;                }
   double                     GetVolume(void)                                    const { return this.m_volume;                }
//--- (1) Set, (2) return order expiration date
   void                       SetExpiration(const datetime time)                       { this.m_expiration=time;              }
   datetime                   GetExpiration(void)                                const { return this.m_expiration;            }
//--- (1) Set, (2) return the flag of the asynchronous sending of a trading request
   void                       SetAsyncMode(const bool async)                           { this.m_async_mode=async;             }
   bool                       GetAsyncMode(void)                                 const { return this.m_async_mode;            }
   
//--- Last request data:
//--- Return (1) executed action type, (2) magic number, (3) order ticket, (4) volume,
//--- (5) open, (6) StopLimit order, (7) StopLoss, (8) TakeProfit price, (9) deviation,
//--- type of (10) order, (11) execution, (12) lifetime, (13) order expiration date,
//--- (14) comment, (15) position ticket, (16) opposite position ticket
   ENUM_TRADE_REQUEST_ACTIONS GetLastRequestAction(void)                         const { return this.m_request.action;        }
   ulong                      GetLastRequestMagic(void)                          const { return this.m_request.magic;         }
   ulong                      GetLastRequestOrder(void)                          const { return this.m_request.order;         }
   double                     GetLastRequestVolume(void)                         const { return this.m_request.volume;        }
   double                     GetLastRequestPrice(void)                          const { return this.m_request.price;         }
   double                     GetLastRequestStopLimit(void)                      const { return this.m_request.stoplimit;     }
   double                     GetLastRequestStopLoss(void)                       const { return this.m_request.sl;            }
   double                     GetLastRequestTakeProfit(void)                     const { return this.m_request.tp;            }
   ulong                      GetLastRequestDeviation(void)                      const { return this.m_request.deviation;     }
   ENUM_ORDER_TYPE            GetLastRequestType(void)                           const { return this.m_request.type;          }
   ENUM_ORDER_TYPE_FILLING    GetLastRequestTypeFilling(void)                    const { return this.m_request.type_filling;  }
   ENUM_ORDER_TYPE_TIME       GetLastRequestTypeTime(void)                       const { return this.m_request.type_time;     }
   datetime                   GetLastRequestExpiration(void)                     const { return this.m_request.expiration;    }
   string                     GetLastRequestComment(void)                        const { return this.m_request.comment;       }
   ulong                      GetLastRequestPosition(void)                       const { return this.m_request.position;      }
   ulong                      GetLastRequestPositionBy(void)                     const { return this.m_request.position_by;   }

//--- Data on the last request result:
//--- Return (1) operation result code, (2) performed deal ticket, (3) placed order ticket,
//--- (4) deal volume confirmed by a broker, (5) deal price confirmed by a broker,
//--- (6) current market Bid (requote) price, (7) current market Ask (requote) price
//--- (8) broker comment to operation (by default, it is filled by the trade server return code description),
//--- (9) request ID set by the terminal when sending, (10) external trading system return code
   uint                       GetResultRetcode(void)                             const { return this.m_result.retcode;        }
   ulong                      GetResultDeal(void)                                const { return this.m_result.deal;           }
   ulong                      GetResultOrder(void)                               const { return this.m_result.order;          }
   double                     GetResultVolume(void)                              const { return this.m_result.volume;         }
   double                     GetResultPrice(void)                               const { return this.m_result.price;          }
   double                     GetResultBid(void)                                 const { return this.m_result.bid;            }
   double                     GetResultAsk(void)                                 const { return this.m_result.ask;            }
   string                     GetResultComment(void)                             const { return this.m_result.comment;        }
   uint                       GetResultRequestID(void)                           const { return this.m_result.request_id;     }
   uint                       GetResultRetcodeEXT(void)                          const { return this.m_result.retcode_external;}

//--- Open a position
   bool                       OpenPosition(const ENUM_POSITION_TYPE type,
                                           const double volume,
                                           const double sl=0,
                                           const double tp=0,
                                           const ulong magic=ULONG_MAX,
                                           const ulong deviation=ULONG_MAX,
                                           const string comment=NULL);
//--- Close a position
   bool                       ClosePosition(const ulong ticket,
                                            const ulong deviation=ULONG_MAX,
                                            const string comment=NULL);
//--- Close a position partially
   bool                       ClosePositionPartially(const ulong ticket,
                                                     const double volume,
                                                     const ulong deviation=ULONG_MAX,
                                                     const string comment=NULL);
//--- Close a position by an opposite one
   bool                       ClosePositionBy(const ulong ticket,const ulong ticket_by);
//--- Modify a position
   bool                       ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE);
//--- Place an order
   bool                       SetOrder(const ENUM_ORDER_TYPE type,
                                       const double volume,
                                       const double price,
                                       const double sl=0,
                                       const double tp=0,
                                       const double price_stoplimit=0,
                                       const ulong magic=ULONG_MAX,
                                       const datetime expiration=0,
                                       const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,
                                       const string comment=NULL);
//--- Remove an order
   bool                       DeleteOrder(const ulong ticket);
//--- Modify an order
   bool                       ModifyOrder(const ulong ticket,
                                          const double price=WRONG_VALUE,
                                          const double sl=WRONG_VALUE,
                                          const double tp=WRONG_VALUE,
                                          const double price_stoplimit=WRONG_VALUE,
                                          const datetime expiration=WRONG_VALUE,
                                          const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE);
   
  };
//+------------------------------------------------------------------+


ここで書いたことを詳しく見てみましょう。

現在の価格を取得するには、取引リクエストが送信される銘柄のプロパティにアクセスする必要があります。関連する価格が必要なため、取引リクエストを送信する直前に取します。これが、MqlTick 構造体型のm_tick 変数を基本取引オブジェクトに直接配置する理由です。銘柄オブジェクトから渡すこともできますが、プロパティを取引オブジェクトに渡すための冗長な(最小ではありますが)コストをかけずに行う方が良いでしょう。

MqlTradeRequest取引リクエスト構造体型のm_request 変数は、すべての取引リクエストプロパティを入力してOrderSend()関数に送信するために使用されます。 MqlTradeResult取引リクエスト結果構造体型のm_result変数も同様に渡されます。これは、取引サーバから回答を受信した際にサーバによって入力されます。サーバに注文を送信した結果が正しくない場合は、取引リクエストの結果構造体のフィールドを読み取って何が起こったかを理解できます。

他のクラスメンバ変数については説明は必要ないと思います。

クラスメソッドの実装を見てみましょう。

取引リクエストのプロパティを設定および取得するメソッド(Set/Getメソッド)は、クラス本体に記述されています。これらのメソッドは、渡された値を適切な変数に書き込むか適切な変数の値を返すだけで、デフォルト値を格納する変数でのみ機能します。つまり、これらのメソッドを使用すると、取引リクエストの必須プロパティを設定できます。さらに、デフォルト値として定義された値を持つようになります。取引リクエストに別の値を1回使用する必要がある場合、取引リクエスト送信メソッドでは、渡された値の1回限りの使用に必要な値を渡すことができます。

最後の取引リクエストのパラメータを返すメソッドは、最後の取引リクエストのプロパティに渡される値を定義し、エラーを排除するか、次のサーバリクエストにこれらの値を使用するための手順を実行します。
メソッドは、対応する取引リクエスト構造体フィールドのコンテンツを返すだけです。リクエストを送信する前に、この構造体(取引リクエストに対応するフィールドの一部)が入力され、サーバにリクエストを送信する関数に渡されます。これは、最後に入力された値を取得する構造体です。

取引リクエストの結果を返すメソッドにより、取引リクエストの処理結果に関するデータを取得できます。リクエストでエラーが発生した場合、retcodeでエラーコードの説明を見ることができます。または、構造体はポジションまたは未決注文のデータで満たされ、request_idがリクエストのコードとなります。これは、OnTradeTransaction()ハンドラで分析してOrderSendAsync()経由でサーバに送信された取引リクエストをリクエスト結果とリンクできます。OnTradeTransaction()はMQL4には存在しないため、このライブラリでは使用せずに、リクエストの非同期送信とその結果を独自に分析します。

クラスコンストラクタ:

//+------------------------------------------------------------------+
//| コンストラクタ                                                     |
//+------------------------------------------------------------------+
CTradeObj::CTradeObj(void) : m_magic(0),
                             m_deviation(5),
                             m_stop_limit(0),
                             m_expiration(0),
                             m_async_mode(false),
                             m_type_filling(ORDER_FILLING_FOK),
                             m_type_expiration(ORDER_TIME_GTC),
                             m_comment(::MQLInfoString(MQL_PROGRAM_NAME)+" by DoEasy"),
                             m_log_level(LOG_LEVEL_ERROR_MSG)
  {
   //--- Margin calculation mode
   this.m_margin_mode=
     (
      #ifdef __MQL5__ (ENUM_ACCOUNT_MARGIN_MODE)::AccountInfoInteger(ACCOUNT_MARGIN_MODE)
      #else /* MQL4 */ ACCOUNT_MARGIN_MODE_RETAIL_HEDGING #endif 
     );
  }
//+------------------------------------------------------------------+


初期化リストで以下の初期値を設定します。

  • マジックナンバー - 0
  • スリッページ - 5ポイント
  • StopLimit注文価格 - 0(なし)
  • 注文有効期限 - 0(なし)
  • リクエストの非同期送信 - 無効
  • 発注ポリシー - FOK
  • 注文有効期限 - なし
  • 注文コメント - 「プログラム名 + by DoEasy」
  • 取引クラス操作ログモード — エラーのみ

クラス本体で、口座に設定された証拠金計算方法をm_margin_mode変数に追加します。
MQL5では、AccountInfoInteger()関数とACCOUNT_MARGIN_MODEプロパティIDを使用して必要な値を取得します。
MQL4では、直ちに証拠金計算をヘッジモード(ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)に設定します。

必要なプロパティの必要な値を取引リクエストに記入するための取引メソッドに渡すことができます。しかし、多くの場合、必要なプロパティは各取引リクエストに対して同じなので、すべてに入力する必要はありません。したがって、デフォルト変数を初期化して、取引メソッドで取引リクエストに使用する値を、サーバにリクエストを送信するメソッドに渡される値またはデフォルトで設定される値のいずれかから選択できる必要があります。

取引リクエストのデフォルトパラメータを初期化するメソッドを記述します。

//+------------------------------------------------------------------+
//| Set default values                                               |
//+------------------------------------------------------------------+
void CTradeObj::Init(const string symbol,
                     const ulong magic,
                     const double volume,
                     const ulong deviation,
                     const int stoplimit,
                     const datetime expiration,
                     const bool async_mode,
                     const ENUM_ORDER_TYPE_FILLING type_filling,
                     const ENUM_ORDER_TYPE_TIME type_expiration,
                     ENUM_LOG_LEVEL log_level)
  {
   this.SetSymbol(symbol);
   this.SetMagic(magic);
   this.SetDeviation(deviation);
   this.SetVolume(volume);
   this.SetExpiration(expiration);
   this.SetTypeFilling(type_filling);
   this.SetTypeExpiration(type_expiration);
   this.SetAsyncMode(async_mode);
   this.SetLogLevel(log_level);
   this.m_symbol_expiration_flags=(int)::SymbolInfoInteger(this.m_symbol,SYMBOL_EXPIRATION_MODE);
   this.m_volume=::SymbolInfoDouble(this.m_symbol,SYMBOL_VOLUME_MIN);
  }
//+------------------------------------------------------------------+


メソッドは、取引要求パラメータの必要な値を受け取ります。メソッド本体では、上記で検討した設定方法を使用して、渡された値が適切な変数に設定されます。許可された注文有効期限モードのフラグは、SYMBOL_EXPIRATION_MODEプロパティIDとともにSymbolInfoInteger()関数を使用して設定されます。適用される数量は、SYMBOL_VOLUME_MINプロパティIDを指定したSymbolInfoDouble()関数を使用して、銘柄に最低限受け入れられる数量です。

以下は、ポジションを開く関数です。

//+------------------------------------------------------------------+
//| Open a position                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::OpenPosition(const ENUM_POSITION_TYPE type,
                             const double volume,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=ULONG_MAX,
                             const ulong deviation=ULONG_MAX,
                             const string comment=NULL)
  {
   //--- If failed to get the current prices, write the error code and description, send the message to the journal and return 'false'
   if(!::SymbolInfoTick(this.m_symbol,this.m_tick))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_PRICE),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action   =  TRADE_ACTION_DEAL;
   this.m_request.symbol   =  this.m_symbol;
   this.m_request.magic    =  (magic==ULONG_MAX ? this.m_magic : magic);
   this.m_request.type     =  OrderTypeByPositionType(type);
   this.m_request.price    =  (type==POSITION_TYPE_BUY ? this.m_tick.ask : this.m_tick.bid);
   this.m_request.volume   =  volume;
   this.m_request.sl       =  sl;
   this.m_request.tp       =  tp;
   this.m_request.deviation=  (deviation==ULONG_MAX ? this.m_deviation : deviation);
   this.m_request.comment  =  (comment==NULL ? this.m_comment : comment);
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         (::OrderSend(m_request.symbol,m_request.type,m_request.volume,m_request.price,(int)m_request.deviation,m_request.sl,m_request.tp,m_request.comment,(int)m_request.magic,m_request.expiration,clrNONE)!=WRONG_VALUE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、ポジションの種類と数量、StopLoss価格とTakeProfit価格、ポジションのマジックナンバー、スリッページ値、コメントを受け取ります。
ストップロス、テイクプロフィット、マジックナンバー、スリッページ、コメントにはデフォルト値が設定されています。メソッドが呼び出されたときにこれらの値が変更されないままの場合、これらの値には、Init()メソッドでデフォルトで設定された値、またはデフォルト値を設定する方法でプログラムから直接設定された値が使用されます。メソッドのロジック全体がコードコメントに記述されています。
ポジションの種類ごとに注文の種類を受信するためにDELib.mqhで記述したOrderTypeByPositionType()関数によって送信された結果は、取引リクエスト構造体の注文の種類を格納するフィールドに送信されます。 メソッドは、渡されたパラメータが検証済みであると仮定して、検証しません。
MQL4では、また、リクエストをサーバに送信した結果を返すときにも何も変更せず、取引リクエストの結果の構造体には入力しません。現在、テストのために取引方法を迅速に収集する必要があります。今後の記事ではすべてを整理します。

以下は、ポジションを決済する関数です。

//+------------------------------------------------------------------+
//| Close a position                                                 |
//+------------------------------------------------------------------+
bool CTradeObj::ClosePosition(const ulong ticket,
                              const ulong deviation=ULONG_MAX,
                              const string comment=NULL)
  {
   //--- If failed to select a position. Write the error code and description, send the message to the journal and return 'false'
   if(!::PositionSelectByTicket(ticket))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_POS),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get a position symbol
   string symbol=::PositionGetString(POSITION_SYMBOL);
   //--- If failed to get the current prices, write the error code and description, send the message to the journal and return 'false'
   if(!::SymbolInfoTick(symbol,this.m_tick))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_PRICE),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get a position type and an order type inverse of the position type
   ENUM_POSITION_TYPE position_type=(ENUM_POSITION_TYPE)::PositionGetInteger(POSITION_TYPE);
   ENUM_ORDER_TYPE type=OrderTypeOppositeByPositionType(position_type);
   //--- Get a position volume and magic number
   double position_volume=::PositionGetDouble(POSITION_VOLUME);
   ulong magic=::PositionGetInteger(POSITION_MAGIC);
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action   =  TRADE_ACTION_DEAL;
   this.m_request.symbol   =  symbol;
   this.m_request.magic    =  magic;
   this.m_request.type     =  type;
   this.m_request.price    =  (position_type==POSITION_TYPE_SELL ? this.m_tick.ask : this.m_tick.bid);
   this.m_request.volume   =  position_volume;
   this.m_request.deviation=  (deviation==ULONG_MAX ? this.m_deviation : deviation);
   this.m_request.comment  =  (comment==NULL ? this.m_comment : comment);
   //--- In case of a hedging account, write the ticket of a closed position to the structure
   if(this.IsHedge())
      this.m_request.position=::PositionGetInteger(POSITION_TICKET);
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderClose((int)m_request.position,m_request.volume,m_request.price,(int)m_request.deviation,clrNONE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、決済されたポジションのチケット、スリッページ、コメントを受け取ります。ここで(他の取引方法と同様に)すべては上で議論したポジションを開く方法に似ています。

以下は、ポジションを部分決済するメソッドです。

//+------------------------------------------------------------------+
//| Close a position partially                                       |
//+------------------------------------------------------------------+
bool CTradeObj::ClosePositionPartially(const ulong ticket,
                                       const double volume,
                                       const ulong deviation=ULONG_MAX,
                                       const string comment=NULL)
  {
   //--- If failed to select a position. Write the error code and description, send the message to the journal and return 'false'
   if(!::PositionSelectByTicket(ticket))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_POS),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get a position symbol
   string symbol=::PositionGetString(POSITION_SYMBOL);
   //--- If failed to get the current prices, write the error code and description, send the message to the journal and return 'false'
   if(!::SymbolInfoTick(symbol,this.m_tick))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_PRICE),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get a position type and an order type inverse of the position type
   ENUM_POSITION_TYPE position_type=(ENUM_POSITION_TYPE)::PositionGetInteger(POSITION_TYPE);
   ENUM_ORDER_TYPE type=OrderTypeOppositeByPositionType(position_type);
   //--- Get a position volume and magic number
   double position_volume=::PositionGetDouble(POSITION_VOLUME);
   ulong magic=::PositionGetInteger(POSITION_MAGIC);
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action   =  TRADE_ACTION_DEAL;
   this.m_request.position =  ticket;
   this.m_request.symbol   =  symbol;
   this.m_request.magic    =  magic;
   this.m_request.type     =  type;
   this.m_request.price    =  (position_type==POSITION_TYPE_SELL ? this.m_tick.ask : this.m_tick.bid);
   this.m_request.volume   =  (volume<position_volume ? volume : position_volume);
   this.m_request.deviation=  (deviation==ULONG_MAX ? this.m_deviation : deviation);
   this.m_request.comment  =  (comment==NULL ? this.m_comment : comment);
   //--- In case of a hedging account, write the ticket of a closed position to the structure
   if(this.IsHedge())
      this.m_request.position=::PositionGetInteger(POSITION_TICKET);
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderClose((int)m_request.position,m_request.volume,m_request.price,(int)m_request.deviation,clrNONE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、決済されたポジションのチケット、スリッページ、コメントを渡します。メソッドに渡された終値が既存のポジション量を超える場合、ポジションは完全に決済されます

以下は、反対方向のポジションによってポジションを決済するメソッドです。

//+------------------------------------------------------------------+
//| Close a position by an opposite one                              |
//+------------------------------------------------------------------+
bool CTradeObj::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
   #ifdef __MQL5__
   //--- If this is not a hedging account. 
   if(::AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
     {
      //--- Close by is available only on hedging accounts.
      //---Write the error code and description, send the message to the journal and return 'false'
      this.m_result.retcode=MSG_ACC_UNABLE_CLOSE_BY;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_ACC_UNABLE_CLOSE_BY));
      return false;
     }
   #endif 
//--- Closed position
   //--- If failed to select a position, write the error code and description, send the message to the journal and return 'false'
   if(!::PositionSelectByTicket(ticket))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_POS),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get a type and magic of a closed position
   ENUM_POSITION_TYPE position_type=(ENUM_POSITION_TYPE)::PositionGetInteger(POSITION_TYPE);
   ulong magic=::PositionGetInteger(POSITION_MAGIC);
   
//--- Opposite position
   //--- If failed to select a position, write the error code and description, send the message to the journal and return 'false'
   if(!::PositionSelectByTicket(ticket_by))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket_by,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_POS),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Get an opposite position type
   ENUM_POSITION_TYPE position_type_by=(ENUM_POSITION_TYPE)::PositionGetInteger(POSITION_TYPE);
   //--- If types of a closed and an opposite position match, write the error code and description, send the message to the journal and return 'false'
   if(position_type==position_type_by)
     {
      this.m_result.retcode=MSG_ACC_SAME_TYPE_CLOSE_BY;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,CMessage::Text(MSG_ACC_SAME_TYPE_CLOSE_BY));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   this.m_request.action      =  TRADE_ACTION_CLOSE_BY;
   this.m_request.position    =  ticket;
   this.m_request.position_by =  ticket_by;
   this.m_request.magic       =  magic;
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderCloseBy((int)m_request.position,(int)m_request.position_by,clrNONE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、決済されたポジションのチケットと反対方向のポジションのチケットを受け取ります。

以下は、ポジションのストップレベルを修正するメソッドです。

//+------------------------------------------------------------------+
//| Modify a position                                                |
//+------------------------------------------------------------------+
bool CTradeObj::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
   //--- If all default values are passed, there is nothing to be modified
   if(sl==WRONG_VALUE && tp==WRONG_VALUE)
     {
      //--- There are no changes in the request - write the error code and description, send the message to the journal and return 'false'
      this.m_result.retcode= #ifdef __MQL5__ TRADE_RETCODE_NO_CHANGES #else 10025 #endif ;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,CMessage::Text(this.m_result.retcode),CMessage::Retcode(this.m_result.retcode));
      return false;
     }
   //--- If failed to select a position, write the error code and description, send the message to the journal and return 'false'
   if(!::PositionSelectByTicket(ticket))
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_POS),CMessage::Text(this.m_result.retcode));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   m_request.action  =  TRADE_ACTION_SLTP;
   m_request.position=  ticket;
   m_request.symbol  =  ::PositionGetString(POSITION_SYMBOL);
   m_request.magic   =  ::PositionGetInteger(POSITION_MAGIC);
   m_request.sl      =  (sl==WRONG_VALUE ? ::PositionGetDouble(POSITION_SL) : sl);
   m_request.tp      =  (tp==WRONG_VALUE ? ::PositionGetDouble(POSITION_TP) : tp);
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderModify((int)m_request.position,::OrderOpenPrice(),m_request.sl,m_request.tp,::OrderExpiration(),clrNONE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、変更されたポジションのチケットと新しいストップロスレベルとテイクプロフィットレベルを受け取ります。

以下は、指値注文を出すメソッドです。

//+------------------------------------------------------------------+
//| Set an order                                                     |
//+------------------------------------------------------------------+
bool CTradeObj::SetOrder(const ENUM_ORDER_TYPE type,
                         const double volume,
                         const double price,
                         const double sl=0,
                         const double tp=0,
                         const double price_stoplimit=0,
                         const ulong magic=ULONG_MAX,
                         const datetime expiration=0,
                         const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC,
                         const string comment=NULL)
  {
   //--- If an invalid order type has been passed, write the error code and description, send the message to the journal and return 'false'
   if(type==ORDER_TYPE_BUY || type==ORDER_TYPE_SELL || type==ORDER_TYPE_CLOSE_BY 
      #ifdef __MQL4__ || type==ORDER_TYPE_BUY_STOP_LIMIT || type==ORDER_TYPE_SELL_STOP_LIMIT #endif )
     {
      this.m_result.retcode=MSG_LIB_SYS_INVALID_ORDER_TYPE;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_INVALID_ORDER_TYPE),OrderTypeDescription(type));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   m_request.action     =  TRADE_ACTION_PENDING;
   m_request.symbol     =  this.m_symbol;
   m_request.magic      =  (magic==ULONG_MAX ? this.m_magic : magic);
   m_request.volume     =  volume;
   m_request.type       =  type;
   m_request.stoplimit  =  price_stoplimit;
   m_request.price      =  price;
   m_request.sl         =  sl;
   m_request.tp         =  tp;
   m_request.type_time  =  type_time;
   m_request.expiration =  expiration;
   m_request.comment    =  (comment==NULL ? this.m_comment : comment);
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         (::OrderSend(m_request.symbol,m_request.type,m_request.volume,m_request.price,(int)m_request.deviation,m_request.sl,m_request.tp,m_request.comment,(int)m_request.magic,m_request.expiration,clrNONE)!=WRONG_VALUE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


このメソッドは、未決注文の種類と数量、始値、StopLoss価格とTakeProfit価格、マジックナンバー、注文の有効期限とその種類、コメントを受け取ります。

以下は、指値注文を削除するメソッドです。

//+------------------------------------------------------------------+
//| Remove an order                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::DeleteOrder(const ulong ticket)
  {
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   m_request.action  =  TRADE_ACTION_REMOVE;
   m_request.order   =  ticket;
   //--- Return the result of sending a request to the server
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderDelete((int)m_request.order,clrNONE)
      #endif 
     );
  }
//+------------------------------------------------------------------+


メソッドは、削除された注文のチケットを受け取ります。

以下は、指値注文を修正するメソッドです。

//+------------------------------------------------------------------+
//| Modify an order                                                  |
//+------------------------------------------------------------------+
bool CTradeObj::ModifyOrder(const ulong ticket,
                            const double price=WRONG_VALUE,
                            const double sl=WRONG_VALUE,
                            const double tp=WRONG_VALUE,
                            const double price_stoplimit=WRONG_VALUE,
                            const datetime expiration=WRONG_VALUE,
                            const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE)
  {
   //--- If failed to select an order, write the error code and description, send the message to the journal and return 'false'
   #ifdef __MQL5__
   if(!::OrderSelect(ticket))
   #else 
   if(!::OrderSelect((int)ticket,SELECT_BY_TICKET))
   #endif 
     {
      this.m_result.retcode=::GetLastError();
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,"#",(string)ticket,": ",CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_SELECT_ORD),CMessage::Text(this.m_result.retcode));
      return false;
     }
   double order_price=::OrderGetDouble(ORDER_PRICE_OPEN);
   double order_sl=::OrderGetDouble(ORDER_SL);
   double order_tp=::OrderGetDouble(ORDER_TP);
   double order_stoplimit=::OrderGetDouble(ORDER_PRICE_STOPLIMIT);
   ENUM_ORDER_TYPE_TIME order_type_time=(ENUM_ORDER_TYPE_TIME)::OrderGetInteger(ORDER_TYPE_TIME);
   datetime order_expiration=(datetime)::OrderGetInteger(ORDER_TIME_EXPIRATION);
   //--- If the default values are passed and the price is equal to the price set in the order, the request is unchanged
   //---Write the error code and description, send the message to the journal and return 'false'
   if(price==order_price && sl==WRONG_VALUE && tp==WRONG_VALUE && price_stoplimit==WRONG_VALUE && type_time==WRONG_VALUE && expiration==WRONG_VALUE)
     {
      this.m_result.retcode = #ifdef __MQL5__ TRADE_RETCODE_NO_CHANGES #else 10025 #endif ;
      this.m_result.comment=CMessage::Text(this.m_result.retcode);
      if(this.m_log_level>LOG_LEVEL_NO_MSG)
         Print(DFUN,CMessage::Text(this.m_result.retcode),CMessage::Retcode(this.m_result.retcode));
      return false;
     }
   //--- Clear the structures
   ::ZeroMemory(this.m_request);
   ::ZeroMemory(this.m_result);
   //--- Fill in the request structure
   m_request.action     =  TRADE_ACTION_MODIFY;
   m_request.order      =  ticket;
   m_request.price      =  (price==WRONG_VALUE ? order_price : price);
   m_request.sl         =  (sl==WRONG_VALUE ? order_sl : sl);
   m_request.tp         =  (tp==WRONG_VALUE ? order_tp : tp);
   m_request.stoplimit  =  (price_stoplimit==WRONG_VALUE ? order_stoplimit : price_stoplimit);
   m_request.type_time  =  (type_time==WRONG_VALUE ? order_type_time : type_time);
   m_request.expiration =  (expiration==WRONG_VALUE ? order_expiration : expiration);
   //--- Return an order modification result
   return
     (
      #ifdef __MQL5__
         !this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)
      #else 
         ::OrderModify((int)m_request.order,m_request.price,m_request.sl,m_request.tp,m_request.expiration,clrNONE)
      #endif 
     );
   Print(DFUN);
  }
//+------------------------------------------------------------------+


このメソッドは、変更された注文のチケット、新しい価格、ストップロス/テイクプロフィット/ストップリミット注文レベル、注文の有効期限とその種類を受け取ります。

すべてのメソッドは、メソッドに渡されるデフォルト値の同一のチェックを備えています。すべてのアクションはコードでコメント化されています。コメントは同じタイプであるため、説明しても意味がありません。

これで、基本取引クラスの最小限の機能の作成は完了です。

銘柄に関連して取引リクエストを送信するため、基本取引オブジェクトを銘柄オブジェクトに配置し、外部からアクセスできるようにします。

\MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh銘柄オブジェクトファイルを開いて TradeObj.mqh取引オブジェクトファイルをインクルードします。

//+------------------------------------------------------------------+
//|                                                       Symbol.mqh |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
#property strict    // mql4で必要
//+------------------------------------------------------------------+
//| ファイルをインクルードする                                                    |
//+------------------------------------------------------------------+
#include "..\BaseObj.mqh"
#include "..\Trade\TradeObj.mqh"
//+------------------------------------------------------------------+


privateセクションで、取引クラスの変数オブジェクトを宣言します

//+------------------------------------------------------------------+
//| Abstract symbol class                                            |
//+------------------------------------------------------------------+
class CSymbol : public CBaseObj
  {
private:
   struct MqlMarginRate
     {
      double         Initial;                                  // initial margin rate
      double         Maintenance;                              // maintenance margin rate
     };
   struct MqlMarginRateMode
     {
      MqlMarginRate  Long;                                     // MarginRate of long positions
      MqlMarginRate  Short;                                    // MarginRate of short positions
      MqlMarginRate  BuyStop;                                  // MarginRate of BuyStop orders
      MqlMarginRate  BuyLimit;                                 // MarginRate of BuyLimit orders
      MqlMarginRate  BuyStopLimit;                             // MarginRate of BuyStopLimit orders
      MqlMarginRate  SellStop;                                 // MarginRate of SellStop orders
      MqlMarginRate  SellLimit;                                // MarginRate of SellLimit orders
      MqlMarginRate  SellStopLimit;                            // MarginRate of SellStopLimit orders
     };
   MqlMarginRateMode m_margin_rate;                            // Margin ratio structure
   MqlBookInfo       m_book_info_array[];                      // Array of the market depth data structures

   long              m_long_prop[SYMBOL_PROP_INTEGER_TOTAL];   // Integer properties
   double            m_double_prop[SYMBOL_PROP_DOUBLE_TOTAL];  // Real properties
   string            m_string_prop[SYMBOL_PROP_STRING_TOTAL];  // String properties
   bool              m_is_change_trade_mode;                   // Flag of changing trading mode for a symbol
   CTradeObj         m_trade;                                  // Trading class object
//--- Return the index of the array the symbol's (1) double and (2) string properties are located at
   int               IndexProp(ENUM_SYMBOL_PROP_DOUBLE property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL;                                    }
   int               IndexProp(ENUM_SYMBOL_PROP_STRING property)  const { return(int)property-SYMBOL_PROP_INTEGER_TOTAL-SYMBOL_PROP_DOUBLE_TOTAL;           }
//--- (1) Fill in all the "margin ratio" symbol properties, (2) initialize the ratios
   bool              MarginRates(void);
   void              InitMarginRates(void);
//--- Reset all symbol object data
   void              Reset(void);
//--- Return the current day of the week
   ENUM_DAY_OF_WEEK  CurrentDayOfWeek(void)              const;

public:
//--- デフォルトのコンストラクタ


クラスのpublicセクションで2つのメソッドを宣言します。

これらは、正しい発注ポリシーを返すメソッド注文の正しい有効期限タイプを返すメソッドです。

public:
//--- Set (1) integer, (2) real and (3) string symbol properties
   void              SetProperty(ENUM_SYMBOL_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                                        }
   void              SetProperty(ENUM_SYMBOL_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;                      }
   void              SetProperty(ENUM_SYMBOL_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;                      }
//--- Return (1) integer, (2) real and (3) string symbol properties from the properties array
   long              GetProperty(ENUM_SYMBOL_PROP_INTEGER property)        const { return this.m_long_prop[property];                                       }
   double            GetProperty(ENUM_SYMBOL_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];                     }
   string            GetProperty(ENUM_SYMBOL_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];                     }

//--- Return the flag of a symbol supporting the property
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_INTEGER property)          { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_DOUBLE property)           { return true; }
   virtual bool      SupportProperty(ENUM_SYMBOL_PROP_STRING property)           { return true; }
   
//--- Return the flag of allowing (1) market, (2) limit, (3) stop (4) and stop limit orders,
//--- the flag of allowing setting (5) StopLoss and (6) TakeProfit orders, (7) as well as closing by an opposite order
   bool              IsMarketOrdersAllowed(void)            const { return((this.OrderModeFlags() & SYMBOL_ORDER_MARKET)==SYMBOL_ORDER_MARKET);             }
   bool              IsLimitOrdersAllowed(void)             const { return((this.OrderModeFlags() & SYMBOL_ORDER_LIMIT)==SYMBOL_ORDER_LIMIT);               }
   bool              IsStopOrdersAllowed(void)              const { return((this.OrderModeFlags() & SYMBOL_ORDER_STOP)==SYMBOL_ORDER_STOP);                 }
   bool              IsStopLimitOrdersAllowed(void)         const { return((this.OrderModeFlags() & SYMBOL_ORDER_STOP_LIMIT)==SYMBOL_ORDER_STOP_LIMIT);     }
   bool              IsStopLossOrdersAllowed(void)          const { return((this.OrderModeFlags() & SYMBOL_ORDER_SL)==SYMBOL_ORDER_SL);                     }
   bool              IsTakeProfitOrdersAllowed(void)        const { return((this.OrderModeFlags() & SYMBOL_ORDER_TP)==SYMBOL_ORDER_TP);                     }
   bool              IsCloseByOrdersAllowed(void)           const;

//--- Return the (1) FOK and (2) IOC filling flag
   bool              IsFillingModeFOK(void)                 const { return((this.FillingModeFlags() & SYMBOL_FILLING_FOK)==SYMBOL_FILLING_FOK);             }
   bool              IsFillingModeIOC(void)                 const { return((this.FillingModeFlags() & SYMBOL_FILLING_IOC)==SYMBOL_FILLING_IOC);             }

//--- Return the flag of order expiration: (1) GTC, (2) DAY, (3) Specified and (4) Specified Day
   bool              IsExpirationModeGTC(void)              const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_GTC)==SYMBOL_EXPIRATION_GTC);    }
   bool              IsExpirationModeDAY(void)              const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_DAY)==SYMBOL_EXPIRATION_DAY);    }
   bool              IsExpirationModeSpecified(void)        const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_SPECIFIED)==SYMBOL_EXPIRATION_SPECIFIED);          }
   bool              IsExpirationModeSpecifiedDay(void)     const { return((this.ExpirationModeFlags() & SYMBOL_EXPIRATION_SPECIFIED_DAY)==SYMBOL_EXPIRATION_SPECIFIED_DAY);  }

//--- Return the description of allowing (1) market, (2) limit, (3) stop and (4) stop limit orders,
//--- the description of allowing (5) StopLoss and (6) TakeProfit orders, (7) as well as closing by an opposite order
   string            GetMarketOrdersAllowedDescription(void)      const;
   string            GetLimitOrdersAllowedDescription(void)       const;
   string            GetStopOrdersAllowedDescription(void)        const;
   string            GetStopLimitOrdersAllowedDescription(void)   const;
   string            GetStopLossOrdersAllowedDescription(void)    const;
   string            GetTakeProfitOrdersAllowedDescription(void)  const;
   string            GetCloseByOrdersAllowedDescription(void)     const;

//--- Return the description of allowing the filling type (1) FOK and (2) IOC, (3) as well as allowed order expiration modes
   string            GetFillingModeFOKAllowedDescrioption(void)   const;
   string            GetFillingModeIOCAllowedDescrioption(void)   const;

//--- Return the description of order expiration: (1) GTC, (2) DAY, (3) Specified and (4) Specified Day
   string            GetExpirationModeGTCDescription(void)        const;
   string            GetExpirationModeDAYDescription(void)        const;
   string            GetExpirationModeSpecifiedDescription(void)  const;
   string            GetExpirationModeSpecDayDescription(void)    const;

//--- Return the description of the (1) status, (2) price type for constructing bars, 
//--- (3) method of calculating margin, (4) instrument trading mode,
//--- (5) deal execution mode for a symbol, (6) swap calculation mode,
//--- (7) StopLoss and TakeProfit lifetime, (8) option type, (9) option rights
//--- flags of (10) allowed order types, (11) allowed filling types,
//--- (12) allowed order expiration modes
   string            GetStatusDescription(void)                   const;
   string            GetChartModeDescription(void)                const;
   string            GetCalcModeDescription(void)                 const;
   string            GetTradeModeDescription(void)                const;
   string            GetTradeExecDescription(void)                const;
   string            GetSwapModeDescription(void)                 const;
   string            GetOrderGTCModeDescription(void)             const;
   string            GetOptionTypeDescription(void)               const;
   string            GetOptionRightDescription(void)              const;
   string            GetOrderModeFlagsDescription(void)           const;
   string            GetFillingModeFlagsDescription(void)         const;
   string            GetExpirationModeFlagsDescription(void)      const;
   
//--- Return (1) execution type, (2) order expiration type equal to 'type' if it is available on a symbol, otherwise - the correct option
   ENUM_ORDER_TYPE_FILLING GetCorrectTypeFilling(const uint type=ORDER_FILLING_RETURN);
   ENUM_ORDER_TYPE_TIME    GetCorrectTypeExpiration(uint expiration=ORDER_TIME_GTC);
//+------------------------------------------------------------------+


クラス本体の外側で実装しましょう。

//+------------------------------------------------------------------+
//| Return an order expiration type equal to 'type',                 |
//| if it is available on a symbol, otherwise, the correct option    |
//| https://www.mql5.com/ru/forum/170952/page4#comment_4128864       |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING CSymbol::GetCorrectTypeFilling(const uint type=ORDER_FILLING_RETURN)
  {
  const ENUM_SYMBOL_TRADE_EXECUTION exe_mode=this.TradeExecutionMode();
  const int filling_mode=this.FillingModeFlags();

  return(
         (filling_mode == 0 || (type >= ORDER_FILLING_RETURN) || ((filling_mode & (type + 1)) != type + 1)) ?
         (((exe_mode == SYMBOL_TRADE_EXECUTION_EXCHANGE) || (exe_mode == SYMBOL_TRADE_EXECUTION_INSTANT)) ?
           ORDER_FILLING_RETURN : ((filling_mode == SYMBOL_FILLING_IOC) ? ORDER_FILLING_IOC : ORDER_FILLING_FOK)) :
         (ENUM_ORDER_TYPE_FILLING)type
        );
  }
//+------------------------------------------------------------------+
//| Return order expiration type equal to 'expiration'               |
//| if it is available on Symb symbol, otherwise - the correct option|
//| https://www.mql5.com/ja/forum/170952/page4#comment_4128871       |
//| Application:                                                     |
//| Request.type_time = GetExpirationType((uint)Expiration);         |
//| 'Expiration' can be datetime                                     |
//| if(Expiration > ORDER_TIME_DAY) Request.expiration = Expiration; |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_TIME CSymbol::GetCorrectTypeExpiration(uint expiration=ORDER_TIME_GTC)
  {
#ifdef __MQL5__
  const int expiration_mode=this.ExpirationModeFlags();
  if((expiration > ORDER_TIME_SPECIFIED_DAY) || (((expiration_mode >> expiration) & 1) == 0))
    {
      if((expiration < ORDER_TIME_SPECIFIED) || (expiration_mode < SYMBOL_EXPIRATION_SPECIFIED))
         expiration=ORDER_TIME_GTC;
      else if(expiration > ORDER_TIME_DAY)
         expiration=ORDER_TIME_SPECIFIED;

      uint i=1 << expiration;
      while((expiration <= ORDER_TIME_SPECIFIED_DAY) && ((expiration_mode & i) != i))
        {
         i <<= 1;
         expiration++;
        }
     }
#endif 
  return (ENUM_ORDER_TYPE_TIME)expiration;
  }
//+------------------------------------------------------------------+


車輪の再発明を避けるために、fxsaberフォーラムメンバーによって説明されたメソッドロジックを使用しました。コードヘッダーには、コードを含む投稿へのリンクがあります。

このロジックの複雑さをすべて理解するのは簡単ではありませんが、信頼できる開発者としてこの関数を公開した人が知人なので、彼に頼ることに決めました。もちろん、メソッドのロジック全体を個別の要素に分割し、広範なメソッドを取得して、それらのロジック全体を記述することは可能です。しかし、メソッドの説明を実装する方が簡単です。
メソッドは、必要な約定ポリシーと注文有効期限タイプを受け取ります。銘柄がこのポリシーまたはタイプをサポートしている場合、それが返されます。銘柄で必要なモードがサポートされていない場合、許可されたモードが返されます。したがって、メソッドは常にサポートされているモード(発注ポリシーモードまたは注文の有効期限モード)を返します。

Publicセクションの銘柄オブジェクト整数プロパティへの単純化されたアクセスのメソッドを持つブロックで、正規化されたロットを返すメソッドの宣言を追加します。

//+------------------------------------------------------------------+
//| Methods of a simplified access to the order object properties    |
//+------------------------------------------------------------------+
//--- Integer properties
   long              Status(void)                                 const { return this.GetProperty(SYMBOL_PROP_STATUS);                                      }
   int               IndexInMarketWatch(void)                     const { return (int)this.GetProperty(SYMBOL_PROP_INDEX_MW);                               }
   bool              IsCustom(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_CUSTOM);                                }
   color             ColorBackground(void)                        const { return (color)this.GetProperty(SYMBOL_PROP_BACKGROUND_COLOR);                     }
   ENUM_SYMBOL_CHART_MODE ChartMode(void)                         const { return (ENUM_SYMBOL_CHART_MODE)this.GetProperty(SYMBOL_PROP_CHART_MODE);          }
   bool              IsExist(void)                                const { return (bool)this.GetProperty(SYMBOL_PROP_EXIST);                                 }
   bool              IsExist(const string name)                   const { return this.SymbolExists(name);                                                   }
   bool              IsSelect(void)                               const { return (bool)this.GetProperty(SYMBOL_PROP_SELECT);                                }
   bool              IsVisible(void)                              const { return (bool)this.GetProperty(SYMBOL_PROP_VISIBLE);                               }
   long              SessionDeals(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_DEALS);                               }
   long              SessionBuyOrders(void)                       const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS);                          }
   long              SessionSellOrders(void)                      const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS);                         }
   long              Volume(void)                                 const { return this.GetProperty(SYMBOL_PROP_VOLUME);                                      }
   long              VolumeHigh(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH);                                  }
   long              VolumeLow(void)                              const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW);                                   }
   datetime          Time(void)                                   const { return (datetime)this.GetProperty(SYMBOL_PROP_TIME);                              }
   int               Digits(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS);                                 }
   int               DigitsLot(void)                              const { return (int)this.GetProperty(SYMBOL_PROP_DIGITS_LOTS);                            }
   int               Spread(void)                                 const { return (int)this.GetProperty(SYMBOL_PROP_SPREAD);                                 }
   bool              IsSpreadFloat(void)                          const { return (bool)this.GetProperty(SYMBOL_PROP_SPREAD_FLOAT);                          }
   int               TicksBookdepth(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TICKS_BOOKDEPTH);                        }
   ENUM_SYMBOL_CALC_MODE TradeCalcMode(void)                      const { return (ENUM_SYMBOL_CALC_MODE)this.GetProperty(SYMBOL_PROP_TRADE_CALC_MODE);      }
   ENUM_SYMBOL_TRADE_MODE TradeMode(void)                         const { return (ENUM_SYMBOL_TRADE_MODE)this.GetProperty(SYMBOL_PROP_TRADE_MODE);          }
   datetime          StartTime(void)                              const { return (datetime)this.GetProperty(SYMBOL_PROP_START_TIME);                        }
   datetime          ExpirationTime(void)                         const { return (datetime)this.GetProperty(SYMBOL_PROP_EXPIRATION_TIME);                   }
   int               TradeStopLevel(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_STOPS_LEVEL);                      }
   int               TradeFreezeLevel(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_TRADE_FREEZE_LEVEL);                     }
   ENUM_SYMBOL_TRADE_EXECUTION TradeExecutionMode(void)           const { return (ENUM_SYMBOL_TRADE_EXECUTION)this.GetProperty(SYMBOL_PROP_TRADE_EXEMODE);  }
   ENUM_SYMBOL_SWAP_MODE SwapMode(void)                           const { return (ENUM_SYMBOL_SWAP_MODE)this.GetProperty(SYMBOL_PROP_SWAP_MODE);            }
   ENUM_DAY_OF_WEEK  SwapRollover3Days(void)                      const { return (ENUM_DAY_OF_WEEK)this.GetProperty(SYMBOL_PROP_SWAP_ROLLOVER3DAYS);        }
   bool              IsMarginHedgedUseLeg(void)                   const { return (bool)this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED_USE_LEG);                 }
   int               ExpirationModeFlags(void)                    const { return (int)this.GetProperty(SYMBOL_PROP_EXPIRATION_MODE);                        }
   int               FillingModeFlags(void)                       const { return (int)this.GetProperty(SYMBOL_PROP_FILLING_MODE);                           }
   int               OrderModeFlags(void)                         const { return (int)this.GetProperty(SYMBOL_PROP_ORDER_MODE);                             }
   ENUM_SYMBOL_ORDER_GTC_MODE OrderModeGTC(void)                  const { return (ENUM_SYMBOL_ORDER_GTC_MODE)this.GetProperty(SYMBOL_PROP_ORDER_GTC_MODE);  }
   ENUM_SYMBOL_OPTION_MODE OptionMode(void)                       const { return (ENUM_SYMBOL_OPTION_MODE)this.GetProperty(SYMBOL_PROP_OPTION_MODE);        }
   ENUM_SYMBOL_OPTION_RIGHT OptionRight(void)                     const { return (ENUM_SYMBOL_OPTION_RIGHT)this.GetProperty(SYMBOL_PROP_OPTION_RIGHT);      }
//--- Real properties
   double            Bid(void)                                    const { return this.GetProperty(SYMBOL_PROP_BID);                                         }
   double            BidHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_BIDHIGH);                                     }
   double            BidLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_BIDLOW);                                      }
   double            Ask(void)                                    const { return this.GetProperty(SYMBOL_PROP_ASK);                                         }
   double            AskHigh(void)                                const { return this.GetProperty(SYMBOL_PROP_ASKHIGH);                                     }
   double            AskLow(void)                                 const { return this.GetProperty(SYMBOL_PROP_ASKLOW);                                      }
   double            Last(void)                                   const { return this.GetProperty(SYMBOL_PROP_LAST);                                        }
   double            LastHigh(void)                               const { return this.GetProperty(SYMBOL_PROP_LASTHIGH);                                    }
   double            LastLow(void)                                const { return this.GetProperty(SYMBOL_PROP_LASTLOW);                                     }
   double            VolumeReal(void)                             const { return this.GetProperty(SYMBOL_PROP_VOLUME_REAL);                                 }
   double            VolumeHighReal(void)                         const { return this.GetProperty(SYMBOL_PROP_VOLUMEHIGH_REAL);                             }
   double            VolumeLowReal(void)                          const { return this.GetProperty(SYMBOL_PROP_VOLUMELOW_REAL);                              }
   double            OptionStrike(void)                           const { return this.GetProperty(SYMBOL_PROP_OPTION_STRIKE);                               }
   double            Point(void)                                  const { return this.GetProperty(SYMBOL_PROP_POINT);                                       }
   double            TradeTickValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE);                            }
   double            TradeTickValueProfit(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_PROFIT);                     }
   double            TradeTickValueLoss(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_VALUE_LOSS);                       }
   double            TradeTickSize(void)                          const { return this.GetProperty(SYMBOL_PROP_TRADE_TICK_SIZE);                             }
   double            TradeContractSize(void)                      const { return this.GetProperty(SYMBOL_PROP_TRADE_CONTRACT_SIZE);                         }
   double            TradeAccuredInterest(void)                   const { return this.GetProperty(SYMBOL_PROP_TRADE_ACCRUED_INTEREST);                      }
   double            TradeFaceValue(void)                         const { return this.GetProperty(SYMBOL_PROP_TRADE_FACE_VALUE);                            }
   double            TradeLiquidityRate(void)                     const { return this.GetProperty(SYMBOL_PROP_TRADE_LIQUIDITY_RATE);                        }
   double            LotsMin(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MIN);                                  }
   double            LotsMax(void)                                const { return this.GetProperty(SYMBOL_PROP_VOLUME_MAX);                                  }
   double            LotsStep(void)                               const { return this.GetProperty(SYMBOL_PROP_VOLUME_STEP);                                 }
   double            VolumeLimit(void)                            const { return this.GetProperty(SYMBOL_PROP_VOLUME_LIMIT);                                }
   double            SwapLong(void)                               const { return this.GetProperty(SYMBOL_PROP_SWAP_LONG);                                   }
   double            SwapShort(void)                              const { return this.GetProperty(SYMBOL_PROP_SWAP_SHORT);                                  }
   double            MarginInitial(void)                          const { return this.GetProperty(SYMBOL_PROP_MARGIN_INITIAL);                              }
   double            MarginMaintenance(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_MAINTENANCE);                          }
   double            MarginLongInitial(void)                      const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_INITIAL);                         }
   double            MarginBuyStopInitial(void)                   const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_INITIAL);                     }
   double            MarginBuyLimitInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_INITIAL);                    }
   double            MarginBuyStopLimitInitial(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_INITIAL);                }
   double            MarginLongMaintenance(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_LONG_MAINTENANCE);                     }
   double            MarginBuyStopMaintenance(void)               const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOP_MAINTENANCE);                 }
   double            MarginBuyLimitMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_LIMIT_MAINTENANCE);                }
   double            MarginBuyStopLimitMaintenance(void)          const { return this.GetProperty(SYMBOL_PROP_MARGIN_BUY_STOPLIMIT_MAINTENANCE);            }
   double            MarginShortInitial(void)                     const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_INITIAL);                        }
   double            MarginSellStopInitial(void)                  const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_INITIAL);                    }
   double            MarginSellLimitInitial(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_INITIAL);                   }
   double            MarginSellStopLimitInitial(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_INITIAL);               }
   double            MarginShortMaintenance(void)                 const { return this.GetProperty(SYMBOL_PROP_MARGIN_SHORT_MAINTENANCE);                    }
   double            MarginSellStopMaintenance(void)              const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOP_MAINTENANCE);                }
   double            MarginSellLimitMaintenance(void)             const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_LIMIT_MAINTENANCE);               }
   double            MarginSellStopLimitMaintenance(void)         const { return this.GetProperty(SYMBOL_PROP_MARGIN_SELL_STOPLIMIT_MAINTENANCE);           }
   double            SessionVolume(void)                          const { return this.GetProperty(SYMBOL_PROP_SESSION_VOLUME);                              }
   double            SessionTurnover(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_TURNOVER);                            }
   double            SessionInterest(void)                        const { return this.GetProperty(SYMBOL_PROP_SESSION_INTEREST);                            }
   double            SessionBuyOrdersVolume(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_BUY_ORDERS_VOLUME);                   }
   double            SessionSellOrdersVolume(void)                const { return this.GetProperty(SYMBOL_PROP_SESSION_SELL_ORDERS_VOLUME);                  }
   double            SessionOpen(void)                            const { return this.GetProperty(SYMBOL_PROP_SESSION_OPEN);                                }
   double            SessionClose(void)                           const { return this.GetProperty(SYMBOL_PROP_SESSION_CLOSE);                               }
   double            SessionAW(void)                              const { return this.GetProperty(SYMBOL_PROP_SESSION_AW);                                  }
   double            SessionPriceSettlement(void)                 const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_SETTLEMENT);                    }
   double            SessionPriceLimitMin(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MIN);                     }
   double            SessionPriceLimitMax(void)                   const { return this.GetProperty(SYMBOL_PROP_SESSION_PRICE_LIMIT_MAX);                     }
   double            MarginHedged(void)                           const { return this.GetProperty(SYMBOL_PROP_MARGIN_HEDGED);                               }
   double            NormalizedPrice(const double price)          const;
   double            NormalizedLot(const double volume)           const;
   double            BidLast(void)                                const;
   double            BidLastHigh(void)                            const;
   double            BidLastLow(void)                             const;
//--- String properties


クラス本体の最後に、銘柄オブジェクトに属する取引オブジェクトを返すメソッドを追加します

   //--- The average weighted session price
   //--- setting the controlled session average weighted price (1) increase, (2) decrease and (3) control value
   //--- getting (4) the change value of the average weighted session price,
   //--- getting the flag of the average weighted session price change exceeding the (5) increase, (6) decrease value
   void              SetControlSessionPriceAWInc(const double value)             { this.SetControlledValueINC(SYMBOL_PROP_SESSION_AW,::fabs(value));                 }
   void              SetControlSessionPriceAWDec(const double value)             { this.SetControlledValueDEC(SYMBOL_PROP_SESSION_AW,::fabs(value));                 }
   void              SetControlSessionPriceAWLevel(const double value)           { this.SetControlledValueLEVEL(SYMBOL_PROP_SESSION_AW,::fabs(value));               }
   double            GetValueChangedSessionPriceAW(void)                   const { return this.GetPropDoubleChangedValue(SYMBOL_PROP_SESSION_AW);                    }
   bool              IsIncreasedSessionPriceAW(void)                       const { return (bool)this.GetPropDoubleFlagINC(SYMBOL_PROP_SESSION_AW);                   }
   bool              IsDecreasedSessionPriceAW(void)                       const { return (bool)this.GetPropDoubleFlagDEC(SYMBOL_PROP_SESSION_AW);                   }

//--- Return a trading object
   CTradeObj        *GetTradeObj(void)                                           { return &this.m_trade; }

  };
//+------------------------------------------------------------------+


銘柄オブジェクトを作成するとすぐに取引オブジェクトが生成され、取引オブジェクトはすべてのフィールドの値の初期化を開始するため、必要なデフォルト値を使用して初期化する必要があります。これを実現するには、CSymbolクラスコンストラクタの最後で、必要なデフォルト値を使用して取引オブジェクトのInit()メソッドを呼び出します

   
//--- Fill in the symbol current data
   for(int i=0;i<SYMBOL_PROP_INTEGER_TOTAL;i++)
      this.m_long_prop_event[i][3]=this.m_long_prop[i];
   for(int i=0;i<SYMBOL_PROP_DOUBLE_TOTAL;i++)
      this.m_double_prop_event[i][3]=this.m_double_prop[i];
   
//--- Update the base object data and search for changes
   CBaseObj::Refresh();
//---
   if(!select)
      this.RemoveFromMarketWatch();

//--- Initializing default values of a trading object
   this.m_trade.Init(this.Name(),0,this.LotsMin(),5,0,0,false,this.GetCorrectTypeFilling(),this.GetCorrectTypeExpiration(),LOG_LEVEL_ERROR_MSG);
  }
//+------------------------------------------------------------------+


メソッドを取引オブジェクトに呼び出すとき、以下を渡します。

  • 銘柄名
  • 銘柄の最小ロット
  • スリッページ(5ポイント)
  • ゼロに等しいStopLoss価格(ストップロスなし)
  • ゼロに等しいTakeProfit価格(テイクプロフィットなし)
  • falseに等しいリクエストの非同期送信フラグ - 同期送信
  • 正しい注文履行ポリシーをすぐに受け取り、取引オブジェクトに設定
  • 注文の有効期間の正しいモードを取得して、取引オブジェクトに設定
  • 取引方法のログレベルを「エラーのみ」に設定

これらの値はデフォルトで取引オブジェクトに設定されますが、上記の各メソッドのSetメソッドを個別に使用していつでも変更できます。あるいは、デフォルト値のままにして、取引メソッドを呼び出すときに別のパラメーターを渡し、リクエストをサーバーに送信するときに一度使用されるようにすることもできます。

クラス本体の外側にロット正規化メソッドを実装します。

//+------------------------------------------------------------------+
//| Return a normalized lot considering symbol properties            |
//+------------------------------------------------------------------+
double CSymbol::NormalizedLot(const double volume) const
  {
   double ml=this.LotsMin();
   double mx=this.LotsMax();
   double ln=::NormalizeDouble(volume,this.DigitsLot());
   return(ln<ml ?ml : ln>mx ?mx : ln);
  }
//+------------------------------------------------------------------+


メソッドは、正規化に必要なロット値を受け取ります。次に、銘柄に許可される最小ロットと最大ロットを取得し、メソッドに渡されるロット値を正規化し、正規化された値を最小ロットと最大ロットと比較するだけで返される値を定義します。メソッドに渡されたロットが最小/最大銘柄ロットより少ない/多い場合、それに応じて最小/最大ロットを返します。それ以外の場合、ロット値の小数点以下の桁数を考慮して正規化されたロットを返します(DigitsLot()メソッド)。

CSymbolクラスを改善しました。

次に、取引メソッドをテストする必要があります。基本取引クラスがまだないため、必要な銘柄の取引オブジェクトにアクセスするためのメソッドを一時的に CEngineライブラリ基本オブジェクトクラスに追加します。これは、すべての重要なライブラリコレクションへのフルアクセスを持つオブジェクトであるため、取引オブジェクトをテストするためのメソッドを配置します。

クラスのメソッドは一時的なものです。後で、値の確認と取引に必要なすべてのメソッドを含む本格的な取引クラスを実装します。

取引オブジェクトのテストに現在必要なすべてのメソッドは、CEngineクラスのpublicセクションに追加されます。

//--- Set the following for the trading classes:
//--- (1) correct filling policy, (2) filling policy,
//--- (3) correct order expiration type, (4) order expiration type,
//--- (5) magic number, (6) comment, (7) slippage, (8) volume, (9) order expiration date,
//--- (10) the flag of asynchronous sending of a trading request, (11) logging level
   void                 SetTradeCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 SetTradeTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL);
   void                 SetTradeCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 SetTradeTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL);
   void                 SetTradeMagic(const ulong magic,const string symbol_name=NULL);
   void                 SetTradeComment(const string comment,const string symbol_name=NULL);
   void                 SetTradeDeviation(const ulong deviation,const string symbol_name=NULL);
   void                 SetTradeVolume(const double volume=0,const string symbol_name=NULL);
   void                 SetTradeExpiration(const datetime expiration=0,const string symbol_name=NULL);
   void                 SetTradeAsyncMode(const bool mode=false,const string symbol_name=NULL);
   void                 SetTradeLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL);
   
//--- Return a symbol trading object by (1) position, (2) order ticket
   CTradeObj           *GetTradeObjByPosition(const ulong ticket);
   CTradeObj           *GetTradeObjByOrder(const ulong ticket);
   
//--- Open (1) Buy, (2) Sell position
   bool                 OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL);
   bool                 OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL);
//--- Modify a position
   bool                 ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE);
//--- Close a position (1) fully, (2) partially, (3) by an opposite one
   bool                 ClosePosition(const ulong ticket);
   bool                 ClosePositionPartially(const ulong ticket,const double volume);
   bool                 ClosePositionBy(const ulong ticket,const ulong ticket_by);
//--- Set (1) BuyStop, (2) BuyLimit, (3) BuyStopLimit pending order
   bool                 PlaceBuyStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceBuyStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- Set (1) SellStop, (2) SellLimit, (3) SellStopLimit pending order
   bool                 PlaceSellStop(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellLimit(const double volume,
                                     const string symbol,
                                     const double price,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
   bool                 PlaceSellStopLimit(const double volume,
                                     const string symbol,
                                     const double price_stop,
                                     const double price_limit,
                                     const double sl=0,
                                     const double tp=0,
                                     const ulong magic=ULONG_MAX,
                                     const string comment=NULL,
                                     const datetime expiration=0,
                                     const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC);
//--- Modify a pending order
   bool                 ModifyOrder(const ulong ticket,
                                    const double price=WRONG_VALUE,
                                    const double sl=WRONG_VALUE,
                                    const double tp=WRONG_VALUE,
                                    const double stoplimit=WRONG_VALUE,
                                    datetime expiration=WRONG_VALUE,
                                    ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE);
//--- Remove a pending order
   bool                 DeleteOrder(const ulong ticket);

//--- Return event (1) milliseconds, (2) reason and (3) source from its 'long' value
   ushort               EventMSC(const long lparam)               const { return this.LongToUshortFromByte(lparam,0);         }
   ushort               EventReason(const long lparam)            const { return this.LongToUshortFromByte(lparam,1);         }
   ushort               EventSource(const long lparam)            const { return this.LongToUshortFromByte(lparam,2);         }

//--- コンストラクタ/デストラクタ
                        CEngine();
                       ~CEngine();
  };
//+------------------------------------------------------------------+


宣言されたメソッドをクラス本体の外側に実装します。

以下は、買いポジションを開くメソッドです。

//+------------------------------------------------------------------+
//| Open Buy position                                                |
//+------------------------------------------------------------------+
bool CEngine::OpenBuy(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.OpenPosition(POSITION_TYPE_BUY,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • ポジションの数量(必須)
  • ポジションを開く銘柄(必須)
  • ポジションに割り当てるマジックナンバー(デフォルトは0)
  • ストップロス(デフォルトで未設定)
  • テイクプロフィット(デフォルトで未設定)
  • ポジションコメント(デフォルトは「プログラム名 + by DoEasy」)

銘柄名によって銘柄を取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
銘柄名によって取引オブジェクトを取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトのポジションを開くためのメソッドの操作結果を返します

以下は、売りポジションを開くメソッドです。

//+------------------------------------------------------------------+
//| Open a Sell position                                             |
//+------------------------------------------------------------------+
bool CEngine::OpenSell(const double volume,const string symbol,const ulong magic=ULONG_MAX,double sl=0,double tp=0,const string comment=NULL)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.OpenPosition(POSITION_TYPE_SELL,volume,sl,tp,magic,trade_obj.GetDeviation(),comment);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • ポジションの数量(必須)
  • ポジションを開く銘柄(必須)
  • ポジションに割り当てるマジックナンバー(デフォルトは0)
  • ストップロス(デフォルトで未設定)
  • テイクプロフィット(デフォルトで未設定)
  • ポジションコメント(デフォルトは「プログラム名 + by DoEasy」)

銘柄名によって銘柄を取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
銘柄名によって取引オブジェクトを取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトのポジションを開くためのメソッドの操作結果を返します

以下は、ポジションのストップレベルとテイクプロフィットを修正するメソッドです。

//+------------------------------------------------------------------+
//| Modify a position                                                |
//+------------------------------------------------------------------+
bool CEngine::ModifyPosition(const ulong ticket,const double sl=WRONG_VALUE,const double tp=WRONG_VALUE)
  {
   CTradeObj *trade_obj=this.GetTradeObjByPosition(ticket);
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.ModifyPosition(ticket,sl,tp);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 変更されたポジションのチケット(必須)
  • 新しいストップロス(デフォルトで変更なし)
  • 新しいテイクプロフィット(デフォルトで変更なし)

以下で検討するGetTradeObjByPosition()メソッドを使用して、ポジションチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトのポジションを修正するためのメソッドの操作結果を返します

以下は、ポジションを完全決済するメソッドです。

//+------------------------------------------------------------------+
//| Close a position in full                                         |
//+------------------------------------------------------------------+
bool CEngine::ClosePosition(const ulong ticket)
  {
   CTradeObj *trade_obj=this.GetTradeObjByPosition(ticket);
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.ClosePosition(ticket);
  }
//+------------------------------------------------------------------+


このメソッドは、決済されたポジションのチケットを受け取ります。

以下で検討するGetTradeObjByPosition()メソッドを使用して、ポジションチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトのポジションを決済するためのメソッドの操作結果を返します

以下は、ポジションを部分決済するメソッドです。

//+------------------------------------------------------------------+
//| Close a position partially                                       |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionPartially(const ulong ticket,const double volume)
  {
   CTradeObj *trade_obj=this.GetTradeObjByPosition(ticket);
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   CSymbol *symbol=this.GetSymbolObjByName(trade_obj.GetSymbol());
   return trade_obj.ClosePositionPartially(ticket,symbol.NormalizedLot(volume));
  }
//+------------------------------------------------------------------+


このメソッドは、決済されたポジションのチケットと数量を受け取ります。

以下で検討するGetTradeObjByPosition()メソッドを使用して、ポジションチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
取引オブジェクトの銘柄名によって銘柄objectを取得します
上記で検討した取引オブジェクトのポジションを部分決済するためのメソッドの操作結果を返しますこのメソッドは、正規化された決済数量を受け取ります

以下は、反対方向のポジションによってポジションを決済するメソッドです。

//+------------------------------------------------------------------+
//| Close a position by an opposite one                              |
//+------------------------------------------------------------------+
bool CEngine::ClosePositionBy(const ulong ticket,const ulong ticket_by)
  {
   CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket);
   if(trade_obj_pos==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   CTradeObj *trade_obj_by=this.GetTradeObjByPosition(ticket_by);
   if(trade_obj_by==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj_pos.ClosePositionBy(ticket,ticket_by);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 決済されたポジションのチケット
  • 反対方向のポジションのチケット

以下で検討するGetTradeObjByPosition()メソッドを使用して、ポジションチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
以下で検討するGetTradeObjByPosition()メソッドを使用して、反対ポジションチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示して falseを返します。
取引オブジェクトのポジションを決済するためのメソッドの操作結果を返します

以下は、BuyStop注文を出すメソッドです。

//+------------------------------------------------------------------+
//| Place BuyStop pending order                                      |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyStop(const double volume,
                           const string symbol,
                           const double price,
                           const double sl=0,
                           const double tp=0,
                           const ulong magic=WRONG_VALUE,
                           const string comment=NULL,
                           const datetime expiration=0,
                           const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 出された注文の数量(必須)
  • 注文銘柄(必須)
  • 注文価格(必須)
  • ストップロス(デフォルトで未設定)
  • テイクプロフィット(デフォルトで未設定)
  • 出された注文のマジックナンバー(デフォルトは0)
  • 出された注文のコメント(デフォルトは「プログラム名 + by DoEasy」)
  • 出された注文の有効期限(デフォルトは「なし」)
  • 出された注文の有効期限の種類(デフォルトは明確的なキャンセル)

銘柄名によって銘柄を取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
銘柄名によって取引オブジェクトを取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトの指値注文を出すためのメソッドの操作結果を返します

以下は、BuyLimit注文を出すメソッドです。

//+------------------------------------------------------------------+
//| Place BuyLimit pending order                                     |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyLimit(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.SetOrder(ORDER_TYPE_BUY_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 出された注文の数量(必須)
  • 注文銘柄(必須)
  • 注文価格(必須)
  • ストップロス(デフォルトで未設定)
  • テイクプロフィット(デフォルトで未設定)
  • 出された注文のマジックナンバー(デフォルトは0)
  • 出された注文のコメント(デフォルトは「プログラム名 + by DoEasy」)
  • 出された注文の有効期限(デフォルトは「なし」)
  • 出された注文の有効期限の種類(デフォルトは明確的なキャンセル)

銘柄名によって銘柄を取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
銘柄名によって取引オブジェクトを取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトの指値注文を出すためのメソッドの操作結果を返します

以下は、BuyStopLimit注文を出すメソッドです。

//+------------------------------------------------------------------+
//| Place BuyStopLimit pending order                                 |
//+------------------------------------------------------------------+
bool CEngine::PlaceBuyStopLimit(const double volume,
                                const string symbol,
                                const double price_stop,
                                const double price_limit,
                                const double sl=0,
                                const double tp=0,
                                const ulong magic=WRONG_VALUE,
                                const string comment=NULL,
                                const datetime expiration=0,
                                const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   #ifdef __MQL5__
      CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
      if(symbol_obj==NULL)
        {
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
         return false;
        }
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
         return false;
        }
      return trade_obj.SetOrder(ORDER_TYPE_BUY_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment);
   //--- MQL4
   #else 
      return true;
   #endif 
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 出された注文の数量(必須)
  • 注文銘柄(必須)
  • BuyStop注文価格(必須)
  • BuyStop注文が発動した後のBuyLimit注文価格(必須)
  • ストップロス(デフォルトで未設定)
  • テイクプロフィット(デフォルトで未設定)
  • 出された注文のマジックナンバー(デフォルトは0)
  • 出された注文のコメント(デフォルトは「プログラム名 + by DoEasy」)
  • 出された注文の有効期限(デフォルトは「なし」)
  • 出された注文の有効期限の種類(デフォルトは明確的なキャンセル)

MQL5:

銘柄名によって銘柄を取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
銘柄名によって取引オブジェクトを取得しますオブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトの指値注文を出すためのメソッドの操作結果を返します

MQL4:

何もせずに、trueを返します。

以下は、SellStopSellLimitSellStopLimit注文を出すメソッドです。

//+------------------------------------------------------------------+
//| Place SellStop pending order                                     |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellStop(const double volume,
                            const string symbol,
                            const double price,
                            const double sl=0,
                            const double tp=0,
                            const ulong magic=WRONG_VALUE,
                            const string comment=NULL,
                            const datetime expiration=0,
                            const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place SellLimit pending order                                    |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellLimit(const double volume,
                             const string symbol,
                             const double price,
                             const double sl=0,
                             const double tp=0,
                             const ulong magic=WRONG_VALUE,
                             const string comment=NULL,
                             const datetime expiration=0,
                             const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
   if(symbol_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
      return false;
     }
   CTradeObj *trade_obj=symbol_obj.GetTradeObj();
   if(trade_obj==NULL)
     {
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.SetOrder(ORDER_TYPE_SELL_LIMIT,volume,price,sl,tp,0,magic,expiration,type_time,comment);
  }
//+------------------------------------------------------------------+
//| Place SellStopLimit pending order                                |
//+------------------------------------------------------------------+
bool CEngine::PlaceSellStopLimit(const double volume,
                                 const string symbol,
                                 const double price_stop,
                                 const double price_limit,
                                 const double sl=0,
                                 const double tp=0,
                                 const ulong magic=WRONG_VALUE,
                                 const string comment=NULL,
                                 const datetime expiration=0,
                                 const ENUM_ORDER_TYPE_TIME type_time=ORDER_TIME_GTC)
  {
   #ifdef __MQL5__
      CSymbol *symbol_obj=this.GetSymbolObjByName(symbol);
      if(symbol_obj==NULL)
        {
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_SYMBOL_ON_LIST));
         return false;
        }
      CTradeObj *trade_obj=symbol_obj.GetTradeObj();
      if(trade_obj==NULL)
        {
         ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
         return false;
        }
      return trade_obj.SetOrder(ORDER_TYPE_SELL_STOP_LIMIT,volume,price_stop,sl,tp,price_limit,magic,expiration,type_time,comment);
   //--- MQL4
   #else 
      return true;
   #endif 
  }
//+------------------------------------------------------------------+


これらのメソッドは、買い指値注文を出すメソッドに似ています。

以下は、指値注文を修正するメソッドです。

//+------------------------------------------------------------------+
//| Modify a pending order                                           |
//+------------------------------------------------------------------+
bool CEngine::ModifyOrder(const ulong ticket,
                          const double price=WRONG_VALUE,
                          const double sl=WRONG_VALUE,
                          const double tp=WRONG_VALUE,
                          const double stoplimit=WRONG_VALUE,
                          datetime expiration=WRONG_VALUE,
                          ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE)
  {
   CTradeObj *trade_obj=this.GetTradeObjByOrder(ticket);
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.ModifyOrder(ticket,price,sl,tp,stoplimit,expiration,type_time);
  }
//+------------------------------------------------------------------+


メソッドは以下を受け取ります。

  • 変更された注文のチケット(必須)
  • 新しい未決注文の価格(デフォルトで変更なし)
  • 新しい未決注文のStopLoss価格(デフォルトで変更なし)
  • 新しい未決注文のTakeProfit価格(デフォルトで変更なし)
  • 新しい未決注文のStopLimit価格(デフォルトで変更なし)
  • 新しい未決注文の有効期限(デフォルトで変更なし)
  • 新しい未決注文の有効期限タイプ(デフォルトで変更なし)

以下で検討するGetTradeObjByOrder()メソッドを使用して、変更された注文のチケットで取引オブジェクトを取得します
オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトの指値注文を変更するためのメソッドの操作結果を返します

以下は、指値注文を削除するメソッドです。

//+------------------------------------------------------------------+
//| Remove a pending order                                           |
//+------------------------------------------------------------------+
bool CEngine::DeleteOrder(const ulong ticket)
  {
   CTradeObj *trade_obj=this.GetTradeObjByOrder(ticket);
   if(trade_obj==NULL)
     {
      //--- Error. Failed to get trading object
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ));
      return false;
     }
   return trade_obj.DeleteOrder(ticket);
  }
//+------------------------------------------------------------------+


メソッドは、削除された注文のチケットを受け取ります。

以下で検討する GetTradeObjByOrder()()メソッドを使用して、注文のチケットで取引オブジェクトを取得します
。<br1/>オブジェクトを取得できない場合は、適切なメッセージを操作ログに表示してfalseを返します。
上記で検討した取引オブジェクトの指値注文を削除するためのメソッドの操作結果を返します

以下は、ポジション注文チケットによって銘柄取引オブジェクトを返すメソッドです。

//+------------------------------------------------------------------+
//| Return a symbol trading object by a position ticket              |
//+------------------------------------------------------------------+
CTradeObj *CEngine::GetTradeObjByPosition(const ulong ticket)
  {
   //--- Get the list of open positions
   CArrayObj *list=this.GetListMarketPosition();
   //--- If failed to get the list of open positions, display the message and return NULL
   if(list==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST));
      return NULL;
     }
   //--- If the list is empty (no open positions), display the message and return NULL
   if(list.Total()==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_ENG_NO_OPEN_POSITIONS));
      return NULL;
     }
   //--- Sort the list by a ticket 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- If failed to get the list of open positions, display the message and return NULL
   if(list==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_MARKET_POS_LIST));
      return NULL;
     }
   //--- If the list is empty (no required ticket), display the message and return NULL
   if(list.Total()==0)
     {
      //--- Error. No open position with #ticket
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NO_OPEN_POSITION_WITH_TICKET),(string)ticket);
      return NULL;
     }
   //--- Get a position with #ticket from the obtained list
   COrder *pos=list.At(0);
   //--- If failed to get the position object, display the message and return NULL
   if(pos==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_POS_OBJ));
      return NULL;
     }
   //--- Get a symbol object by name
   CSymbol * symbol_obj=this.GetSymbolObjByName(pos.Symbol());
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Get and return the trading object from the symbol object
   CTradeObj *obj=symbol_obj.GetTradeObj();
   return obj;
  }
//+------------------------------------------------------------------+
//| Return a symbol trading object by an order ticket                |
//+------------------------------------------------------------------+
CTradeObj *CEngine::GetTradeObjByOrder(const ulong ticket)
  {
   //--- Get the list of placed orders
   CArrayObj *list=this.GetListMarketPendings();
   //--- If failed to get the list of placed orders, display the message and return NULL
   if(list==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST));
      return NULL;
     }
   //--- If the list is empty (no placed orders), display the message and return NULL
   if(list.Total()==0)
     {
      ::Print(DFUN,CMessage::Text(MSG_ENG_NO_PLACED_ORDERS));
      return NULL;
     }
   //--- Sort the list by a ticket 
   list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,ticket,EQUAL);
   //--- If failed to get the list of placed orders, display the message and return NULL
   if(list==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_ENG_FAILED_GET_PENDING_ORD_LIST));
      return NULL;
     }
   //--- If the list is empty (no required ticket), display the message and return NULL
   if(list.Total()==0)
     {
      //--- Error. No placed order with #ticket
      ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_NO_PLACED_ORDER_WITH_TICKET),(string)ticket);
      return NULL;
     }
   //--- Get an order with #ticket from the obtained list
   COrder *ord=list.At(0);
   //--- If failed to get an object order, display the message and return NULL
   if(ord==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ));
      return NULL;
     }
   //--- Get a symbol object by name
   CSymbol *symbol_obj=this.GetSymbolObjByName(ord.Symbol());
   //--- If failed to get the symbol object, display the message and return NULL
   if(symbol_obj==NULL)
     {
      ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ));
      return NULL;
     }
   //--- Get and return the trading object from the symbol object
   CTradeObj *obj=symbol_obj.GetTradeObj();
   return obj;
  }
//+--------------------------------------------------------------------+


どちらのメソッドもほとんど同じですが、1番目のものではすべてのポジションのリストが取得される一方、2番目ではすべての未決注文のリストが取得されます。残りのロジックは両方のメソッドで完全に同一であり、コードでコメントされています。

以下は、銘柄コレクションリストにあるすべての銘柄または指定された単一の銘柄のすべての銘柄の取引オブジェクトでの発注ポリシー有効な発注ポリシーを設定するメソッドです。

//+------------------------------------------------------------------+
//| Set the valid filling policy                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeCorrectTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   //--- Declare the empty pointer to a symbol object
   CSymbol *symbol=NULL;
   //--- If a symbol name passed in the method inputs is not set, specify a filling policy for all symbols
   if(symbol_name==NULL)
     {
      //--- get the list of all used symbols
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      //--- In a loop by the list of symbol objects
      for(int i=0;i<total;i++)
        {
         //--- get the next symbol object
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         //--- get a trading object from a symbol object 
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         //--- set correct filling policy to the trading object (the default is "fill or kill")
         obj.SetTypeFilling(symbol.GetCorrectTypeFilling(type));
        }
     }
   //--- If a symbol name is specified in the method inputs, set the filling policy only for the specified symbol
   else
     {
      //--- Get a symbol object by a symbol name
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      //--- get a trading object from a symbol object 
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      //--- set correct filling policy to the trading object (the default is "fill or kill")
      obj.SetTypeFilling(symbol.GetCorrectTypeFilling(type));
     }
  }
//+------------------------------------------------------------------+
//| Set the filling policy                                           |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeTypeFilling(const ENUM_ORDER_TYPE_FILLING type=ORDER_FILLING_FOK,const string symbol_name=NULL)
  {
   //--- Declare the empty pointer to a symbol object
   CSymbol *symbol=NULL;
   //--- If a symbol name passed in the method inputs is not set, specify a filling policy for all symbols
   if(symbol_name==NULL)
     {
      //--- get the list of all used symbols
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      //--- In a loop by the list of symbol objects
      for(int i=0;i<total;i++)
        {
         //--- get the next symbol object
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         //--- get a trading object from a symbol object 
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         //--- for the trading object, set a filling policy passed to the method in the inputs (the default is "fill or kill")
         obj.SetTypeFilling(type);
        }
     }
   //--- If a symbol name is specified in the method inputs, set the filling policy only for the specified symbol
   else
     {
      //--- Get a symbol object by a symbol name
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      //--- get a trading object from a symbol object 
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      //--- for the trading object, set a filling policy passed to the method in the inputs (the default is "fill or kill")
      obj.SetTypeFilling(type);
     }
  }
//+------------------------------------------------------------------+


メソッドは、発注ポリシー(デフォルトは「FOK」)と銘柄(デフォルトは銘柄コレクションのすべての銘柄)を受け取ります。

メソッドのロジックはコードでコメントされ、非常にわかりやすくなっています。ご質問がある場合は、下のコメント欄でお気軽にお問い合わせください。

銘柄取引オブジェクトのデフォルト値を設定する他のメソッドのロジックは同じで、コメントされていません。いずれの場合でも、これら2つのメソッドを使用してロジックを学習できます。

以下は、デフォルト値を銘柄取引オブジェクトに設定する残りのすべてのメソッドです。

//+------------------------------------------------------------------+
//| Set a correct order expiration type                              |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeCorrectTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetTypeExpiration(symbol.GetCorrectTypeExpiration(type));
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetTypeExpiration(symbol.GetCorrectTypeExpiration(type));
     }
  }
//+------------------------------------------------------------------+
//| Set an order expiration type                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeTypeExpiration(const ENUM_ORDER_TYPE_TIME type=ORDER_TIME_GTC,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetTypeExpiration(type);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetTypeExpiration(type);
     }
  }
//+------------------------------------------------------------------+
//| Set a magic number for trading objects of all symbols            |
//+------------------------------------------------------------------+
void CEngine::SetTradeMagic(const ulong magic,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetMagic(magic);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetMagic(magic);
     }
  }
//+------------------------------------------------------------------+
//| Set a comment for trading objects of all symbols                 |
//+------------------------------------------------------------------+
void CEngine::SetTradeComment(const string comment,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetComment(comment);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetComment(comment);
     }
  }
//+------------------------------------------------------------------+
//| Set a slippage                                                   |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeDeviation(const ulong deviation,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetDeviation(deviation);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetDeviation(deviation);
     }
  }
//+------------------------------------------------------------------+
//| Set a volume for trading objects of all symbols                  |
//+------------------------------------------------------------------+
void CEngine::SetTradeVolume(const double volume=0,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetVolume(volume!=0 ? symbol.NormalizedLot(volume) : symbol.LotsMin());
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetVolume(volume!=0 ? symbol.NormalizedLot(volume) : symbol.LotsMin());
     }
  }
//+------------------------------------------------------------------+
//| Set an order expiration date                                     |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeExpiration(const datetime expiration=0,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetExpiration(expiration);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetExpiration(expiration);
     }
  }
//+------------------------------------------------------------------+
//| Set the flag of asynchronous sending of trading requests         |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeAsyncMode(const bool mode=false,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetAsyncMode(mode);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetAsyncMode(mode);
     }
  }
//+------------------------------------------------------------------+
//| Set a logging level of trading requests                          |
//| for trading objects of all symbols                               |
//+------------------------------------------------------------------+
void CEngine::SetTradeLogLevel(const ENUM_LOG_LEVEL log_level=LOG_LEVEL_ERROR_MSG,const string symbol_name=NULL)
  {
   CSymbol *symbol=NULL;
   if(symbol_name==NULL)
     {
      CArrayObj *list=this.GetListAllUsedSymbols();
      if(list==NULL || list.Total()==0)
         return;
      int total=list.Total();
      for(int i=0;i<total;i++)
        {
         symbol=list.At(i);
         if(symbol==NULL)
            continue;
         CTradeObj *obj=symbol.GetTradeObj();
         if(obj==NULL)
            continue;
         obj.SetLogLevel(log_level);
        }
     }
   else
     {
      symbol=this.GetSymbolObjByName(symbol_name);
      if(symbol==NULL)
         return;
      CTradeObj *obj=symbol.GetTradeObj();
      if(obj==NULL)
         return;
      obj.SetLogLevel(log_level);
     }
  }
//+------------------------------------------------------------------+


銘柄取引オブジェクトをテストするために、CEngineクラスにすべての補助的な一時メソッドを用意しました。

既存のクロスプラットフォーム取引方法(まだ初期段階ですが)により、テストEAでのMQL5またはMQL4の条件付きコンパイルを回避できます。これで、テストEAのすべての取引機能はどのプラットフォームでも同じままです。後に、ライブラリ取引クラスとの連携を改善して、プログラムで効率的に作業するための機能全体を取得します。

基本取引オブジェクトのテスト

銘柄取引オブジェクトをテストするには、前の記事のテストEAを使用し、名がrあ取引オブジェクトを操作するために取引機能を調整します。取引リクエストの値の確認はまだありませんが、これにより無効なパラメータへの応答をテストできます。このような応答は後で実装されます。

\MQL5\Experts\TestDoEasy\Part21\で、EAをTestDoEasyPart21.mq5として保存します。

まず、標準ライブラリCTrade取引クラスのインクルードおよびCTradeクラス型の取引オブジェクトの宣言を削除します。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart20.mq5 |
//|                        Copyright 2018, MetaQuotes Software Corp. |
//|                             https://mql5.com/ja/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://mql5.com/ja/users/artmedia70"
#property version   "1.00"
//--- include
#include <DoEasy\Engine.mqh>
#ifdef __MQL5__
#include <Trade\Trade.mqh>
#endif 
//--- 列挙体
enum ENUM_BUTTONS
  {
   BUTT_BUY,
   BUTT_BUY_LIMIT,
   BUTT_BUY_STOP,
   BUTT_BUY_STOP_LIMIT,
   BUTT_CLOSE_BUY,
   BUTT_CLOSE_BUY2,
   BUTT_CLOSE_BUY_BY_SELL,
   BUTT_SELL,
   BUTT_SELL_LIMIT,
   BUTT_SELL_STOP,
   BUTT_SELL_STOP_LIMIT,
   BUTT_CLOSE_SELL,
   BUTT_CLOSE_SELL2,
   BUTT_CLOSE_SELL_BY_BUY,
   BUTT_DELETE_PENDING,
   BUTT_CLOSE_ALL,
   BUTT_PROFIT_WITHDRAWAL,
   BUTT_SET_STOP_LOSS,
   BUTT_SET_TAKE_PROFIT,
   BUTT_TRAILING_ALL
  };
#define TOTAL_BUTT   (20)
//--- 構造体
struct SDataButt
  {
   string      name;
   string      text;
  };
//--- 入力変数
input ulong             InpMagic             =  123;  // Magic number
input double            InpLots              =  0.1;  // Lots
input uint              InpStopLoss          =  50;   // StopLoss in points
input uint              InpTakeProfit        =  50;   // TakeProfit in points
input uint              InpDistance          =  50;   // Pending orders distance (points)
input uint              InpDistanceSL        =  50;   // StopLimit orders distance (points)
input uint              InpSlippage          =  0;    // Slippage in points
input double            InpWithdrawal        =  10;   // Withdrawal funds (in tester)
input uint              InpButtShiftX        =  40;   // Buttons X shift 
input uint              InpButtShiftY        =  10;   // Buttons Y shift 
input uint              InpTrailingStop      =  50;   // Trailing Stop (points)
input uint              InpTrailingStep      =  20;   // Trailing Step (points)
input uint              InpTrailingStart     =  0;    // Trailing Start (points)
input uint              InpStopLossModify    =  20;   // StopLoss for modification (points)
input uint              InpTakeProfitModify  =  60;   // TakeProfit for modification (points)
input ENUM_SYMBOLS_MODE InpModeUsedSymbols   =  SYMBOLS_MODE_CURRENT;   // Mode of used symbols list
input string            InpUsedSymbols       =  "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY";  // List of used symbols (comma - separator)

//--- グローバル変数
CEngine        engine;
#ifdef __MQL5__
CTrade         trade;
#endif 
SDataButt      butt_data[TOTAL_BUTT];
string         prefix;
double         lot;
double         withdrawal=(InpWithdrawal<0.1 ?0.1 : InpWithdrawal);
ulong          magic_number;
uint           stoploss;
uint           takeprofit;
uint           distance_pending;
uint           distance_stoplimit;
uint           slippage;
bool           trailing_on;
double         trailing_stop;
double         trailing_step;
uint           trailing_start;
uint           stoploss_to_modify;
uint           takeprofit_to_modify;
int            used_symbols_mode;
string         used_symbols;
string         array_used_symbols[];
//+------------------------------------------------------------------+


OnInit()ハンドラで、CTrade取引クラスの「取引」オブジェクトへのパラメータ設定を削除します

//--- Set trailing activation button status
   ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on);

//--- Set CTrade trading class parameters
#ifdef __MQL5__
   trade.SetDeviationInPoints(slippage);
   trade.SetExpertMagicNumber(magic_number);
   trade.SetTypeFillingBySymbol(Symbol());
   trade.SetMarginMode();
   trade.LogLevel(LOG_LEVEL_NO);
#endif 
//--- Create and check the resource files


次に、検索機能(Ctrl+F)を使用して「trade」文字列を検索し、標準ライブラリの取引メソッドの呼び出しを必要なものに置き換えます。

例えば、以下

                  COrder* position=list_positions.At(index);
                  if(position!=NULL)
                    {
                     //--- Get a ticket of a position with the highest profit and close the position by a ticket
                     #ifdef __MQL5__
                        trade.PositionClose(position.Ticket());
                     #else 
                        PositionClose(position.Ticket(),position.Volume());
                     #endif 
                    }


このように置き換えます。

                  COrder* position=list_positions.At(index);
                  if(position!=NULL)
                    {
                     //--- Get a ticket of a position with the highest profit and close the position by a ticket
                     engine.ClosePosition(position.Ticket());
                    }


標準ライブラリ取引メソッドの呼び出しを見つけながら、それらを自分のメソッドの呼び出しに置き換えるだけです。

結果として生じるパネルボタン押下ハンドラを考えてみましょう。新しい取引メソッドのすべての呼び出しは、色付きで強調表示されています。

//+------------------------------------------------------------------+
//| Handle pressing the buttons                                      |
//+------------------------------------------------------------------+
void PressButtonEvents(const string button_name)
  {
   string comment="";
   //--- ボタン名を文字列IDに変換する
   string button=StringSubstr(button_name,StringLen(prefix));
   //--- ボタンが押下された場合
   if(ButtonState(button_name))
     {
      //--- BUTT_BUYボタンが押下されたら、買いポジションを開く
      if(button==EnumToString(BUTT_BUY))
        {
         //--- StopLevelに相対した正しいストップロスとテイクプロフィット価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_BUY,0,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_BUY,0,takeprofit);
         //--- 買いポジションを開く
         engine.OpenBuy(lot,Symbol(),magic_number,sl,tp);   // No comment - the default comment is to be set
        }
      //--- BUTT_BUY_LIMITボタンが押下されたら、BuyLimit注文を出す
      else if(button==EnumToString(BUTT_BUY_LIMIT))
        {
         //--- StopLevelに相対した正しい注文配置を取得する
         double price_set=CorrectPricePending(Symbol(),ORDER_TYPE_BUY_LIMIT,distance_pending);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_BUY_LIMIT,price_set,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_BUY_LIMIT,price_set,takeprofit);
         //--- BuyLimit注文を設定する
         engine.PlaceBuyLimit(lot,Symbol(),price_set,sl,tp,magic_number,TextByLanguage("Отложенный BuyLimit","Pending BuyLimit order"));
        }
      //--- BUTT_BUY_STOPボタンが押下されたら、BuyStopを設定する
      else if(button==EnumToString(BUTT_BUY_STOP))
        {
         //--- StopLevelに相対した正しい注文配置を取得する
         double price_set=CorrectPricePending(Symbol(),ORDER_TYPE_BUY_STOP,distance_pending);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_BUY_STOP,price_set,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_BUY_STOP,price_set,takeprofit);
         //--- BuyStop注文を設定する
         engine.PlaceBuyStop(lot,Symbol(),price_set,sl,tp,magic_number,TextByLanguage("Отложенный BuyStop","Pending BuyStop order"));
        }
      //--- BUTT_BUY_STOP_LIMITボタンが押下されたら、BuyStopLimitを設定する
      else if(button==EnumToString(BUTT_BUY_STOP_LIMIT))
        {
         //--- StopLevelに相対した正しいBuyStop注文配置を取得する
         double price_set_stop=CorrectPricePending(Symbol(),ORDER_TYPE_BUY_STOP,distance_pending);
         //--- StopLevelを考慮して、BuyStopレベルに相対したBuyLimit注文価格を計算する
         double price_set_limit=CorrectPricePending(Symbol(),ORDER_TYPE_BUY_LIMIT,distance_stoplimit,price_set_stop);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_BUY_STOP,price_set_limit,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_BUY_STOP,price_set_limit,takeprofit);
         //--- BuyStopLimit注文を設定する
         engine.PlaceBuyStopLimit(lot,Symbol(),price_set_stop,price_set_limit,sl,tp,magic_number,TextByLanguage("Отложенный BuyStopLimit","Pending BuyStopLimit order"));
        }
      //--- BUTT_SELLボタンが押下されたら、売りポジションを開く
      else if(button==EnumToString(BUTT_SELL))
        {
         //--- StopLevelに相対した正しいストップロスとテイクプロフィット価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_SELL,0,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_SELL,0,takeprofit);
         //--- 売りポジションを開く
         engine.OpenSell(lot,Symbol(),magic_number,sl,tp);  // No comment - the default comment is to be set
        }
      //--- BUTT_SELL_LIMITボタンが押下されたら、SellLimitを設定する
      else if(button==EnumToString(BUTT_SELL_LIMIT))
        {
         //--- StopLevelに相対した正しい注文配置を取得する
         double price_set=CorrectPricePending(Symbol(),ORDER_TYPE_SELL_LIMIT,distance_pending);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_SELL_LIMIT,price_set,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_SELL_LIMIT,price_set,takeprofit);
         //--- SellLimit注文を設定する
         engine.PlaceSellLimit(lot,Symbol(),price_set,sl,tp,magic_number,TextByLanguage("Отложенный SellLimit","Pending SellLimit order"));
        }
      //--- BUTT_SELL_STOPボタンが押下されたら、SellStopを設定する
      else if(button==EnumToString(BUTT_SELL_STOP))
        {
         //--- StopLevelに相対した正しい注文配置を取得する
         double price_set=CorrectPricePending(Symbol(),ORDER_TYPE_SELL_STOP,distance_pending);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_SELL_STOP,price_set,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_SELL_STOP,price_set,takeprofit);
         //--- SellStop注文を設定する
         engine.PlaceSellStop(lot,Symbol(),price_set,sl,tp,magic_number,TextByLanguage("Отложенный SellStop","Pending SellStop order"));
        }
      //--- BUTT_SELL_STOP_LIMITボタンが押下されたら、SellStopLimitを設定する
      else if(button==EnumToString(BUTT_SELL_STOP_LIMIT))
        {
         //--- StopLevelに相対した正しいSellStop注文価格を取得する
         double price_set_stop=CorrectPricePending(Symbol(),ORDER_TYPE_SELL_STOP,distance_pending);
         //--- StopLevelを考慮して、SellStopレベルに相対したSellLimit注文価格を計算する
         double price_set_limit=CorrectPricePending(Symbol(),ORDER_TYPE_SELL_LIMIT,distance_stoplimit,price_set_stop);
         //--- StopLevelを考慮して、発注レベルに対する正しいストップロスとテイクプロフィットの価格を取得する
         double sl=CorrectStopLoss(Symbol(),ORDER_TYPE_SELL_STOP,price_set_limit,stoploss);
         double tp=CorrectTakeProfit(Symbol(),ORDER_TYPE_SELL_STOP,price_set_limit,takeprofit);
         //--- SellStopLimit注文を設定する
         engine.PlaceSellStopLimit(lot,Symbol(),price_set_stop,price_set_limit,sl,tp,magic_number,TextByLanguage("Отложенный SellStopLimit","Pending SellStopLimit order"));
        }
      //--- BUTT_CLOSE_BUYボタンが押下されたら、最大利益を持つ買いポジションを決済する
      else if(button==EnumToString(BUTT_CLOSE_BUY))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list=engine.GetListMarketPosition();
         //--- リストから買いポジションのみを選択する
         list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ買いポジションのインデックスを取得する
         int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL);
         if(index>WRONG_VALUE)
           {
            //--- Get the Buy position object and close a position by ticket
            COrder* position=list.At(index);
            if(position!=NULL)
               engine.ClosePosition((ulong)position.Ticket());
           }
        }
      //--- BUTT_CLOSE_BUY2ボタンが押下されたら、最大利益を持つ買いポジションを半分決済する
      else if(button==EnumToString(BUTT_CLOSE_BUY2))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list=engine.GetListMarketPosition();
         //--- リストから買いポジションのみを選択する
         list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ買いポジションのインデックスを取得する
         int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL);
         if(index>WRONG_VALUE)
           {
            COrder* position=list.At(index);
            if(position!=NULL)
              {
               //--- If this is a hedge account, close the half of the Buy position by the ticket
               if(engine.IsHedge())
                  engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0);
               //--- If this is a netting account, open a Sell position with the half of the Buy position volume
               else
                  engine.OpenSell(NormalizeLot(position.Symbol(),position.Volume()/2.0),Symbol(),magic_number,position.StopLoss(),position.TakeProfit(),"Частичное закрытие Buy #"+(string)position.Ticket());
              }
           }
        }
      //--- BUTT_CLOSE_BUY_BY_SELLボタンが押下されたら、最大利益を持つ買いポジションを反対方向の売りで決済する
      else if(button==EnumToString(BUTT_CLOSE_BUY_BY_SELL))
        {
         //--- In case of a hedging account
         if(engine.IsHedge())
           {
            //--- すべてのポジションのリストを取得する
            CArrayObj* list_buy=engine.GetListMarketPosition();
            //--- リストから買いポジションのみを選択する
            list_buy=CSelect::ByOrderProperty(list_buy,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
            //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
            list_buy.Sort(SORT_BY_ORDER_PROFIT_FULL);
            //--- 最大の利益を持つ買いポジションのインデックスを取得する
            int index_buy=CSelect::FindOrderMax(list_buy,ORDER_PROP_PROFIT_FULL);
            //--- すべてのポジションのリストを取得する
            CArrayObj* list_sell=engine.GetListMarketPosition();
            //--- リストから売りポジションのみを選択する
            list_sell=CSelect::ByOrderProperty(list_sell,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
            //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
            list_sell.Sort(SORT_BY_ORDER_PROFIT_FULL);
            //--- 最大の利益を持つ売りポジションのインデックスを取得する
            int index_sell=CSelect::FindOrderMax(list_sell,ORDER_PROP_PROFIT_FULL);
            if(index_buy>WRONG_VALUE && index_sell>WRONG_VALUE)
              {
               //--- 最大の利益を持つ買いポジションを選択する
               COrder* position_buy=list_buy.At(index_buy);
               //--- 最大の利益を持つ売りポジションを選択する
               COrder* position_sell=list_sell.At(index_sell);
               //--- 買いポジションを反対の売りポジションによって決済する
               if(position_buy!=NULL && position_sell!=NULL)
                  engine.ClosePositionBy((ulong)position_buy.Ticket(),(ulong)position_sell.Ticket());
              }
           }
        }
      //--- BUTT_CLOSE_SELLボタンが押下されたら、最大利益を持つ売りポジションを決済する
      else if(button==EnumToString(BUTT_CLOSE_SELL))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list=engine.GetListMarketPosition();
         //--- リストから売りポジションのみを選択する
         list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ売りポジションのインデックスを取得する
         int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL);
         if(index>WRONG_VALUE)
           {
            //--- Get the Sell position object and close a position by ticket
            COrder* position=list.At(index);
            if(position!=NULL)
               engine.ClosePosition((ulong)position.Ticket());
           }
        }
      //--- BUTT_CLOSE_SELL2ボタンが押下されたら、最大利益を持つ売りポジションを半分決済する
      else if(button==EnumToString(BUTT_CLOSE_SELL2))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list=engine.GetListMarketPosition();
         //--- リストから売りポジションのみを選択する
         list=CSelect::ByOrderProperty(list,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ売りポジションのインデックスを取得する
         int index=CSelect::FindOrderMax(list,ORDER_PROP_PROFIT_FULL);
         if(index>WRONG_VALUE)
           {
            COrder* position=list.At(index);
            if(position!=NULL)
              {
               //--- If this is a hedge account, close the half of the Sell position by the ticket
               if(engine.IsHedge())
                  engine.ClosePositionPartially((ulong)position.Ticket(),position.Volume()/2.0);
               //--- If this is a netting account, open a Buy position with the half of the Sell position volume
               else
                  engine.OpenBuy(NormalizeLot(position.Symbol(),position.Volume()/2.0),Symbol(),position.Magic(),position.StopLoss(),position.TakeProfit(),"Partial closure Buy #"+(string)position.Ticket());
              }
           }
        }
      //--- BUTT_CLOSE_SELL_BY_BUYボタンが押下されたら、最大利益を持つ売りポジションを反対方向の買いで決済する
      else if(button==EnumToString(BUTT_CLOSE_SELL_BY_BUY))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list_sell=engine.GetListMarketPosition();
         //--- リストから売りポジションのみを選択する
         list_sell=CSelect::ByOrderProperty(list_sell,ORDER_PROP_TYPE,POSITION_TYPE_SELL,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list_sell.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ売りポジションのインデックスを取得する
         int index_sell=CSelect::FindOrderMax(list_sell,ORDER_PROP_PROFIT_FULL);
         //--- すべてのポジションのリストを取得する
         CArrayObj* list_buy=engine.GetListMarketPosition();
         //--- リストから買いポジションのみを選択する
         list_buy=CSelect::ByOrderProperty(list_buy,ORDER_PROP_TYPE,POSITION_TYPE_BUY,EQUAL);
         //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
         list_buy.Sort(SORT_BY_ORDER_PROFIT_FULL);
         //--- 最大の利益を持つ買いポジションのインデックスを取得する
         int index_buy=CSelect::FindOrderMax(list_buy,ORDER_PROP_PROFIT_FULL);
         if(index_sell>WRONG_VALUE && index_buy>WRONG_VALUE)
           {
            //--- 最大の利益を持つ売りポジションを選択する
            COrder* position_sell=list_sell.At(index_sell);
            //--- 最大の利益を持つ買いポジションを選択する
            COrder* position_buy=list_buy.At(index_buy);
            if(position_sell!=NULL && position_buy!=NULL)
              {
               //--- 売りポジションを反対の買いポジションによって決済する
               engine.ClosePositionBy((ulong)position_sell.Ticket(),(ulong)position_buy.Ticket());
              }
           }
        }
      //--- BUTT_CLOSE_ALLボタンが押下されたら、最小利益を持つポジションから初めて、すべてのポジションを決済する
      else if(button==EnumToString(BUTT_CLOSE_ALL))
        {
         //--- すべてのポジションのリストを取得する
         CArrayObj* list=engine.GetListMarketPosition();
         if(list!=NULL)
           {
            //--- 手数料とスワップを考慮して、リストを利益順に並べ替える
            list.Sort(SORT_BY_ORDER_PROFIT_FULL);
            int total=list.Total();
            //--- 最小の利益を持つポジションからの反復処理
            for(int i=0;i<total;i++)
              {
               COrder* position=list.At(i);
               if(position==NULL)
                  continue;
               //--- 個々のポジションをチケットで決済する
               engine.ClosePosition((ulong)position.Ticket());
              }
           }
        }
      //--- If the BUTT_DELETE_PENDING button is pressed: Remove the first pending order
      else if(button==EnumToString(BUTT_DELETE_PENDING))
        {
         //--- Get the list of all orders
         CArrayObj* list=engine.GetListMarketPendings();
         if(list!=NULL)
           {
            //--- Sort the list by placement time
            list.Sort(SORT_BY_ORDER_TIME_OPEN);
            int total=list.Total();
            //--- In the loop from the position with the most amount of time
            for(int i=total-1;i>=0;i--)
              {
               COrder* order=list.At(i);
               if(order==NULL)
                  continue;
               //--- delete the order by its ticket
               engine.DeleteOrder((ulong)order.Ticket());
              }
           }
        }
      //--- BUTT_PROFIT_WITHDRAWALボタンが押下されたら、口座から出金する
      if(button==EnumToString(BUTT_PROFIT_WITHDRAWAL))
        {
         //--- プログラムがテスターで起動された場合
         if(MQLInfoInteger(MQL_TESTER))
           {
            //--- 資金出金のエミュレーション
            TesterWithdrawal(withdrawal);
           }
        }
      //--- If the BUTT_SET_STOP_LOSS button is pressed: Place StopLoss to all orders and positions where it is not present
      if(button==EnumToString(BUTT_SET_STOP_LOSS))
        {
         SetStopLoss();
        }
      //--- If the BUTT_SET_TAKE_PROFIT button is pressed: Place TakeProfit to all orders and positions where it is not present
      if(button==EnumToString(BUTT_SET_TAKE_PROFIT))
        {
         SetTakeProfit();
        }
      //--- 0.1秒待つ
      Sleep(100);
      //--- "Unpress" the button (if this is not a trailing button)
      if(button!=EnumToString(BUTT_TRAILING_ALL))
         ButtonState(button_name,false);
      //--- If the BUTT_TRAILING_ALL button is pressed
      else
        {
         //--- Set the color of the active button
         ButtonState(button_name,true);
         trailing_on=true;
        }
      //--- re-draw the chart
      ChartRedraw();
     }
   //--- Return the inactive button color (if this is a trailing button)
   else if(button==EnumToString(BUTT_TRAILING_ALL))
     {
      ButtonState(button_name,false);
      trailing_on=false;
      //--- re-draw the chart
      ChartRedraw();
     }
  }
//+------------------------------------------------------------------+


ここでは、CTrade取引クラスメソッドを呼び出す他の改良されたEA関数を検討しません。以下の添付ファイルですべてのデータを見つけることができます。

単にEAをコンパイルしてテスターで起動できます。
さまざまなパネルボタンをクリックし、取引オブジェクトが操作可能であることを確認します。


最初の銘柄取引オブジェクトは意図したとおりに機能しています。
効率的で便利な作業を行うために必要な複数の改善はまだ実装されていません。

次の段階

次の目標は、銘柄取引オブジェクトにアクセスする際に使用される本格的なクラスの開発です。

現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問、コメント、提案はコメント欄にお願いします。

目次に戻る

シリーズのこれまでの記事:

第1部: 概念、データ管理
第2部: 過去の注文と取引のコレクション
第3部: 注文と取引のコレクション、検索と並び替え
第4部: 取引イベント概念
第5部: 取引イベントのクラスとコレクション取引イベントのプログラムへの送信
第6部: ネッティング勘定イベント
第7部: StopLimit注文発動イベント、注文およびポジション変更イベントの機能の準備
第8部: 注文とポジションの変更イベント
第9部: MQL4との互換性 - データの準備
第10部: MQL4との互換性 - ポジションオープンイベントと指値注文発動イベント
第11部: MQL4との互換性 - ポジション決済イベント
第12部: 口座オブジェクトクラスと口座オブジェクトコレクション
第13部: 口座オブジェクトイベント第14部: 銘柄オブジェクト
第15部: 銘柄オブジェクトコレクション
第16部: 銘柄コレクションイベント
第17部: ライブラリオブジェクトの相互作用
第18部:口座と他のライブラリオブジェクトの相互作用
第19部:ライブラリメッセージのクラス
第20部:プログラムリソースの作成と格納

 

MetaQuotes Software Corp.によりロシア語から翻訳された
元の記事: https://www.mql5.com/ru/articles/7229

添付されたファイル |
MQL5.zip (3567.29 KB)
MQL4.zip (3567.28 KB)
メリルパターンに基づくストラテジービルダー メリルパターンに基づくストラテジービルダー

前回の記事では、通貨シンボルチャートの価格値や標準MetaTrader5インジケータの値(ATR、WPR、CCI、RSIなど)など、さまざまなデータにメリルパターンを適用することを考察しました。 今回はメリルパターンに基づいて戦略構築セットを作成してみましょう。

MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第10部): プログラムリソースの作成と格納 MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第10部): プログラムリソースの作成と格納

この記事では、プログラムのソースコードにデータを保存し、それらから音声ファイルとグラフィックファイルを作成する方法について説明します。アプリケーションを開発するとき、多くの場合、音声と画像が必要です。MQL言語には、このようなデータを使用するいくつかの方法があります。

クロスプラットフォーム グリッドEAの開発(最終パート):収益性を高める方法と多様化 クロスプラットフォーム グリッドEAの開発(最終パート):収益性を高める方法と多様化

このシリーズのこれまでの記事では、多かれ少なかれ収益性の高いグリッドEAを作成するためのさまざまな方法を試しました。 今回は多様化を通じてEAの収益性を高めます。 究極の目標は、最大20% 以下のドローダウンで年間100%の利益を達成することです。

MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第22部): 取引クラス - 基本取引クラス、制限の検証 MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第22部): 取引クラス - 基本取引クラス、制限の検証

この記事では、ライブラリベースの取引クラスの開発を開始し、最初のバージョンに取引操作を行うためのアクセス許可の初期検証を追加します。さらに、基本取引クラスの機能とコンテンツをわずかながら拡張します。