MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第21部): 取引クラス - 基本クロスプラットフォーム取引オブジェクト
内容
この記事では、取引クラスという、新しい幅広いトピックを開始します。概念
いつでもデータに簡単にアクセスできるというのはよいことですが、取引に適用できないとすれば、そのデータは役に立ちません。これは、既存の機能とともに取引機能が必要であることを意味します。
このセクションではすべてを段階的に行うので、セクションは比較的大きくなります。
- 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を返します。
以下は、SellStop、SellLimit、SellStopLimit注文を出すメソッドです。
//+------------------------------------------------------------------+ //| 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 Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7229
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索