MetaTraderプログラムを簡単かつ迅速に開発するためのライブラリ(第28部): 指値取引リクエストの決済、削除、変更
Artyom Trishkin | 16 3月, 2020
内容
これは保留中リクエストの概念に関する3番目の記事です。本稿では、ポジションの決済、注文の削除、およびポジション、ストップ注文と変更可能な指値注文パラメータの変更のためのメソッドを作成することにより、コンセプトのテストを完了します。
さらに、2つの注文とポジションのプロパティ値(注文の執行と有効期限タイプ)の戻り値を追加することにより、抽象注文クラスをわずかに改善します。基本的なクロスプラットフォーム取引オブジェクトのすべての取引方法のコードは、わずかに最適化されています。ここでこの変更について説明する意味はありません。代わりに、変更されたメソッドの一例を表示します。
データの準備
抽象注文の追加プロパティと保留中リクエストクラスのメッセージを説明するテキストメッセージが必要になるので、
Datas.mqhファイルにこれらのメッセージのインデックスを追加します。
エラー処理時のEAの動作を説明する列挙からMSG_ORD_TIME_EXP, // Expiration date MSG_ORD_TYPE_FILLING, // Type of execution by remainder MSG_ORD_TYPE_TIME, // Order lifetime MSG_ORD_TYPE, // Type
...
MSG_LIB_TEXT_PEND_REQUEST_CREATED, // Pending request created MSG_LIB_TEXT_PEND_REQUEST_DELETED, // Pending request is removed due to its expiration MSG_LIB_TEXT_PEND_REQUEST_EXECUTED, // Pending request is removed due to its execution
宣言されたインデックスに対応するテキストメッセージも追加します。
{"Дата экспирации","Date of expiration"}, {"Тип исполнения по остатку","Order filling type"}, {"Время жизни ордера","Order lifetime"}, {"Тип","Type"},
...
{"Создан отложенный запрос","Pending request created"}, {"Отложенный запрос удалён в связи с окончанием времени его действия","Pending request deleted due to expiration"}, {"Отложенный запрос удалён в связи с его исполнением","Pending request deleted due to execution"},
抽象注文オブジェクトにさらに2つのプロパティを追加するため、Defines.mqhファイルでそのプロパティを変更します。
2つの新しいプロパティを整数注文プロパティのブロックに追加します。整数プロパティの総数は24から26に増えます。
//+------------------------------------------------------------------+ //| 注文、取引、ポジションの整数型プロパティ | //+------------------------------------------------------------------+ enum ENUM_ORDER_PROP_INTEGER { ORDER_PROP_TICKET = 0, // 注文チケット ORDER_PROP_MAGIC, // Real order magic number ORDER_PROP_TIME_OPEN, // Open time in milliseconds (MQL5 Deal time) ORDER_PROP_TIME_CLOSE, // Close time in milliseconds (MQL5 Execution or removal time - ORDER_TIME_DONE) ORDER_PROP_TIME_EXP, // 注文有効期限(未決注文用) ORDER_PROP_TYPE_FILLING, // Type of execution by remainder ORDER_PROP_TYPE_TIME, // Order lifetime ORDER_PROP_STATUS, // 注文ステータス(ENUM_ORDER_STATUS列挙体から) ORDER_PROP_TYPE, // Order/deal type ORDER_PROP_REASON, // 取引/注文/ポジション理由またはソース ORDER_PROP_STATE, // 注文ステータス(ENUM_ORDER_STATE列挙体から) ORDER_PROP_POSITION_ID, // ポジションID ORDER_PROP_POSITION_BY_ID, // 反対側のポジションID ORDER_PROP_DEAL_ORDER_TICKET, // Ticket of the order that triggered a deal ORDER_PROP_DEAL_ENTRY, // 取引の方向 – IN、OUT、IN/OUT ORDER_PROP_TIME_UPDATE, // Position change time in milliseconds ORDER_PROP_TICKET_FROM, // 親注文チケット ORDER_PROP_TICKET_TO, // 派生注文チケット ORDER_PROP_PROFIT_PT, // 利益(ポイント) ORDER_PROP_CLOSE_BY_SL, // ストップロスによる決済のフラグ ORDER_PROP_CLOSE_BY_TP, // テイクプロフィットによる決済のフラグ ORDER_PROP_MAGIC_ID, // Order's "magic number" ID ORDER_PROP_GROUP_ID1, // First order/position group ID ORDER_PROP_GROUP_ID2, // Second order/position group ID ORDER_PROP_PEND_REQ_ID, // Pending request ID ORDER_PROP_DIRECTION, // Type by direction (Buy, Sell) }; #define ORDER_PROP_INTEGER_TOTAL (26) // Total number of integer properties #define ORDER_PROP_INTEGER_SKIP (0) // Number of order properties not used in sorting //+------------------------------------------------------------------+
注文をこれらの2つのプロパティによって並び替える機能を追加します。
//+------------------------------------------------------------------+ //| Possible criteria of sorting orders and deals | //+------------------------------------------------------------------+ #define FIRST_ORD_DBL_PROP (ORDER_PROP_INTEGER_TOTAL-ORDER_PROP_INTEGER_SKIP) #define FIRST_ORD_STR_PROP (ORDER_PROP_INTEGER_TOTAL+ORDER_PROP_DOUBLE_TOTAL-ORDER_PROP_INTEGER_SKIP) enum ENUM_SORT_ORDERS_MODE { //--- 整数型プロパティによって並び替える SORT_BY_ORDER_TICKET = 0, // Sort by an order ticket SORT_BY_ORDER_MAGIC, // Sort by an order magic number SORT_BY_ORDER_TIME_OPEN, // Sort by an order open time in milliseconds SORT_BY_ORDER_TIME_CLOSE, // Sort by an order close time in milliseconds SORT_BY_ORDER_TIME_EXP, // Sort by an order expiration date SORT_BY_ORDER_TYPE_FILLING, // Sort by execution type by remainder SORT_BY_ORDER_TYPE_TIME, // Sort by order lifetime SORT_BY_ORDER_STATUS, // Sort by an order status (market order/pending order/deal/balance and credit operation) SORT_BY_ORDER_TYPE, // Sort by an order type SORT_BY_ORDER_REASON, // Sort by a deal/order/position reason/source SORT_BY_ORDER_STATE, // Sort by an order status SORT_BY_ORDER_POSITION_ID, // Sort by a position ID SORT_BY_ORDER_POSITION_BY_ID, // Sort by an opposite position ID SORT_BY_ORDER_DEAL_ORDER, // Sort by the order a deal is based on SORT_BY_ORDER_DEAL_ENTRY, // Sort by a deal direction – IN, OUT or IN/OUT SORT_BY_ORDER_TIME_UPDATE, // Sort by position change time in seconds SORT_BY_ORDER_TICKET_FROM, // Sort by a parent order ticket SORT_BY_ORDER_TICKET_TO, // Sort by a derived order ticket SORT_BY_ORDER_PROFIT_PT, // Sort by order profit in points SORT_BY_ORDER_CLOSE_BY_SL, // Sort by the flag of closing an order by StopLoss SORT_BY_ORDER_CLOSE_BY_TP, // Sort by the flag of closing an order by TakeProfit SORT_BY_ORDER_MAGIC_ID, // Sort by an order/position "magic number" ID SORT_BY_ORDER_GROUP_ID1, // Sort by the first order/position group ID SORT_BY_ORDER_GROUP_ID2, // Sort by the second order/position group ID SORT_BY_ORDER_PEND_REQ_ID, // Sort by a pending request ID SORT_BY_ORDER_DIRECTION, // Sort by direction (Buy, Sell) //--- 実数型プロパティによって並び替える SORT_BY_ORDER_PRICE_OPEN = FIRST_ORD_DBL_PROP, // Sort by open price SORT_BY_ORDER_PRICE_CLOSE, // Sort by close price SORT_BY_ORDER_SL, // Sort by StopLoss price SORT_BY_ORDER_TP, // Sort by TakeProfit price SORT_BY_ORDER_PROFIT, // Sort by profit SORT_BY_ORDER_COMMISSION, // Sort by commission SORT_BY_ORDER_SWAP, // Sort by swap SORT_BY_ORDER_VOLUME, // Sort by volume SORT_BY_ORDER_VOLUME_CURRENT, // Sort by unexecuted volume SORT_BY_ORDER_PROFIT_FULL, // Sort by profit+commission+swap SORT_BY_ORDER_PRICE_STOP_LIMIT, // Sort by Limit order when StopLimit order is activated //--- 文字列型プロパティによって並び替える SORT_BY_ORDER_SYMBOL = FIRST_ORD_STR_PROP, // Sort by symbol SORT_BY_ORDER_COMMENT, // Sort by comment SORT_BY_ORDER_COMMENT_EXT, // Sort by custom comment SORT_BY_ORDER_EXT_ID // Sort by order ID in an external trading system }; //+------------------------------------------------------------------+
サーバエラーを受信した場合、Sleep()で待機して残りのプログラムロジックの実行を遅延させる代わりに常にデフォルトで保留中リクエストを作成するため、エラー処理時のEAの動作を説明する列挙から保留中リクエスト作成オプションを削除します。
//+------------------------------------------------------------------+ //| EA behavior when handling errors | //+------------------------------------------------------------------+ enum ENUM_ERROR_HANDLING_BEHAVIOR { ERROR_HANDLING_BEHAVIOR_BREAK, // Abort trading attempt ERROR_HANDLING_BEHAVIOR_CORRECT, // Correct invalid parameters ERROR_HANDLING_BEHAVIOR_PENDING_REQUEST, // Create a pending request }; //+------------------------------------------------------------------+
列挙は次のようになります。
//+------------------------------------------------------------------+ //| EA behavior when handling errors | //+------------------------------------------------------------------+ enum ENUM_ERROR_HANDLING_BEHAVIOR { ERROR_HANDLING_BEHAVIOR_BREAK, // Abort trading attempt ERROR_HANDLING_BEHAVIOR_CORRECT, // Correct invalid parameters }; //+------------------------------------------------------------------+
また、サーバの戻りコードの処理方法を説明する列挙からもこのオプションを削除します。
//+------------------------------------------------------------------+ //| The methods of handling errors and server return codes | //+------------------------------------------------------------------+ enum ENUM_ERROR_CODE_PROCESSING_METHOD { ERROR_CODE_PROCESSING_METHOD_OK, // No errors ERROR_CODE_PROCESSING_METHOD_DISABLE, // Disable trading for the EA ERROR_CODE_PROCESSING_METHOD_EXIT, // Exit the trading method ERROR_CODE_PROCESSING_METHOD_CORRECT, // Correct trading request parameters and repeat ERROR_CODE_PROCESSING_METHOD_REFRESH, // Update data and repeat ERROR_CODE_PROCESSING_METHOD_PENDING, // Create a pending request ERROR_CODE_PROCESSING_METHOD_WAIT, // Wait and repeat }; //+------------------------------------------------------------------+
列挙は次のようになります。
//+------------------------------------------------------------------+ //| The methods of handling errors and server return codes | //+------------------------------------------------------------------+ enum ENUM_ERROR_CODE_PROCESSING_METHOD { ERROR_CODE_PROCESSING_METHOD_OK, // No errors ERROR_CODE_PROCESSING_METHOD_DISABLE, // Disable trading for the EA ERROR_CODE_PROCESSING_METHOD_EXIT, // Exit the trading method ERROR_CODE_PROCESSING_METHOD_CORRECT, // Correct trading request parameters and repeat ERROR_CODE_PROCESSING_METHOD_REFRESH, // Update data and repeat ERROR_CODE_PROCESSING_METHOD_WAIT, // Wait and repeat }; //+------------------------------------------------------------------+
保留中リクエストパラメータにいくつかの新しいプロパティを追加します。Defines.mqhへの依存をなくすために、保留中リクエストの可能な並べ替え基準を持つ列挙を最後に追加します。これは、そのようなリクエストを見つけるために必要です。
//+------------------------------------------------------------------+ //| Possible pending request sorting criteria | //+------------------------------------------------------------------+ enum ENUM_SORT_PEND_REQ_MODE { SORT_BY_PEND_REQ_ID = 0, // Sort by ID SORT_BY_PEND_REQ_TYPE, // Sort by type SORT_BY_PEND_REQ_TICKET, // Sort by ticket }; //+------------------------------------------------------------------+
Order.mqhファイルのCOrder抽象注文クラスに必要な変更を追加します。
メソッドのブロックに新しいプロパティを返すメソッドを追加して、抽象注文オブジェクトの整数プロパティに簡単にアクセスできるようにします。
//+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Return (1) ticket, (2) parent order ticket, (3) derived order ticket, (4) magic number, (5) order reason, //--- (6) position ID, (7) opposite position ID, (8) first group ID, (9) second group ID, //--- (10) pending request ID, (11) magic number ID, (12) type, (13) flag of closing by StopLoss, //--- (14) flag of closing by TakeProfit (15) open time, (16) close time, //--- (17) order expiration date, (18) state, (19) status, (20) type by direction, (21) execution type by remainder, (22) order lifetime long Ticket(void) const { return this.GetProperty(ORDER_PROP_TICKET); } long TicketFrom(void) const { return this.GetProperty(ORDER_PROP_TICKET_FROM); } long TicketTo(void) const { return this.GetProperty(ORDER_PROP_TICKET_TO); } long Magic(void) const { return this.GetProperty(ORDER_PROP_MAGIC); } long Reason(void) const { return this.GetProperty(ORDER_PROP_REASON); } long PositionID(void) const { return this.GetProperty(ORDER_PROP_POSITION_ID); } long PositionByID(void) const { return this.GetProperty(ORDER_PROP_POSITION_BY_ID); } long MagicID(void) const { return this.GetProperty(ORDER_PROP_MAGIC_ID); } long GroupID1(void) const { return this.GetProperty(ORDER_PROP_GROUP_ID1); } long GroupID2(void) const { return this.GetProperty(ORDER_PROP_GROUP_ID2); } long PendReqID(void) const { return this.GetProperty(ORDER_PROP_PEND_REQ_ID); } long TypeOrder(void) const { return this.GetProperty(ORDER_PROP_TYPE); } bool IsCloseByStopLoss(void) const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_SL); } bool IsCloseByTakeProfit(void) const { return (bool)this.GetProperty(ORDER_PROP_CLOSE_BY_TP); } long TimeOpen(void) const { return this.GetProperty(ORDER_PROP_TIME_OPEN); } long TimeClose(void) const { return this.GetProperty(ORDER_PROP_TIME_CLOSE); } datetime TimeExpiration(void) const { return (datetime)this.GetProperty(ORDER_PROP_TIME_EXP); } ENUM_ORDER_STATE State(void) const { return (ENUM_ORDER_STATE)this.GetProperty(ORDER_PROP_STATE); } ENUM_ORDER_STATUS Status(void) const { return (ENUM_ORDER_STATUS)this.GetProperty(ORDER_PROP_STATUS); } ENUM_ORDER_TYPE TypeByDirection(void) const { return (ENUM_ORDER_TYPE)this.GetProperty(ORDER_PROP_DIRECTION); } ENUM_ORDER_TYPE_FILLING TypeFilling(void) const { return (ENUM_ORDER_TYPE_FILLING)this.GetProperty(ORDER_PROP_TYPE_FILLING); } ENUM_ORDER_TYPE_TIME TypeTime(void) const { return (ENUM_ORDER_TYPE_TIME)this.GetProperty(ORDER_PROP_TYPE_TIME); }
メソッドは、これらのプロパティに対応する整数パラメータに設定された値を返すだけです。
クラスのクローズドコンストラクタに2つの新しい注文オブジェクトプロパティへの代入を追加します。
//+------------------------------------------------------------------+ //| Closedパラメトリックコンストラクタ | //+------------------------------------------------------------------+ COrder::COrder(ENUM_ORDER_STATUS order_status,const ulong ticket) { //--- 整数型プロパティを保存する this.m_ticket=ticket; this.m_long_prop[ORDER_PROP_STATUS] = order_status; this.m_long_prop[ORDER_PROP_MAGIC] = this.OrderMagicNumber(); this.m_long_prop[ORDER_PROP_TICKET] = this.OrderTicket(); this.m_long_prop[ORDER_PROP_TIME_EXP] = this.OrderExpiration(); this.m_long_prop[ORDER_PROP_TYPE_FILLING] = this.OrderTypeFilling(); this.m_long_prop[ORDER_PROP_TYPE_TIME] = this.OrderTypeTime(); this.m_long_prop[ORDER_PROP_TYPE] = this.OrderType(); this.m_long_prop[ORDER_PROP_STATE] = this.OrderState(); this.m_long_prop[ORDER_PROP_DIRECTION] = this.OrderTypeByDirection(); this.m_long_prop[ORDER_PROP_POSITION_ID] = this.OrderPositionID(); this.m_long_prop[ORDER_PROP_REASON] = this.OrderReason(); this.m_long_prop[ORDER_PROP_DEAL_ORDER_TICKET] = this.DealOrderTicket(); this.m_long_prop[ORDER_PROP_DEAL_ENTRY] = this.DealEntry(); this.m_long_prop[ORDER_PROP_POSITION_BY_ID] = this.OrderPositionByID(); this.m_long_prop[ORDER_PROP_TIME_OPEN] = this.OrderOpenTimeMSC(); this.m_long_prop[ORDER_PROP_TIME_CLOSE] = this.OrderCloseTimeMSC(); this.m_long_prop[ORDER_PROP_TIME_UPDATE] = this.PositionTimeUpdateMSC(); //--- 実数型プロパティを保存する this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_OPEN)] = this.OrderOpenPrice(); this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_CLOSE)] = this.OrderClosePrice(); this.m_double_prop[this.IndexProp(ORDER_PROP_PROFIT)] = this.OrderProfit(); this.m_double_prop[this.IndexProp(ORDER_PROP_COMMISSION)] = this.OrderCommission(); this.m_double_prop[this.IndexProp(ORDER_PROP_SWAP)] = this.OrderSwap(); this.m_double_prop[this.IndexProp(ORDER_PROP_VOLUME)] = this.OrderVolume(); this.m_double_prop[this.IndexProp(ORDER_PROP_SL)] = this.OrderStopLoss(); this.m_double_prop[this.IndexProp(ORDER_PROP_TP)] = this.OrderTakeProfit(); this.m_double_prop[this.IndexProp(ORDER_PROP_VOLUME_CURRENT)] = this.OrderVolumeCurrent(); this.m_double_prop[this.IndexProp(ORDER_PROP_PRICE_STOP_LIMIT)] = this.OrderPriceStopLimit(); //--- 文字列プロパティを保存する this.m_string_prop[this.IndexProp(ORDER_PROP_SYMBOL)] = this.OrderSymbol(); this.m_string_prop[this.IndexProp(ORDER_PROP_COMMENT)] = this.OrderComment(); this.m_string_prop[this.IndexProp(ORDER_PROP_EXT_ID)] = this.OrderExternalID(); //--- 追加の整数型プロパティを保存する this.m_long_prop[ORDER_PROP_PROFIT_PT] = this.ProfitInPoints(); this.m_long_prop[ORDER_PROP_TICKET_FROM] = this.OrderTicketFrom(); this.m_long_prop[ORDER_PROP_TICKET_TO] = this.OrderTicketTo(); this.m_long_prop[ORDER_PROP_CLOSE_BY_SL] = this.OrderCloseByStopLoss(); this.m_long_prop[ORDER_PROP_CLOSE_BY_TP] = this.OrderCloseByTakeProfit(); this.m_long_prop[ORDER_PROP_MAGIC_ID] = this.GetMagicID(); this.m_long_prop[ORDER_PROP_GROUP_ID1] = this.GetGroupID1(); this.m_long_prop[ORDER_PROP_GROUP_ID2] = this.GetGroupID2(); this.m_long_prop[ORDER_PROP_PEND_REQ_ID] = this.GetPendReqID(); //--- 追加の実数型プロパティを保存する this.m_double_prop[this.IndexProp(ORDER_PROP_PROFIT_FULL)] = this.ProfitFull(); //--- Save additional string properties this.m_string_prop[this.IndexProp(ORDER_PROP_COMMENT_EXT)] = ""; } //+------------------------------------------------------------------+
プロパティを取得するためにOrderTypeFilling()およびOrderTypeTime()によって返される値は、注文プロパティ配列の適切な値に追加されます。
2つの新しいプロパティの説明をメソッドに追加して、注文オブジェクトの整数プロパティの説明を返します。
//+------------------------------------------------------------------+ //| 注文の整数型プロパティの説明を返す | //+------------------------------------------------------------------+ string COrder::GetPropertyDescription(ENUM_ORDER_PROP_INTEGER property) { return ( //--- 一般的なプロパティ property==ORDER_PROP_MAGIC ? CMessage::Text(MSG_ORD_MAGIC)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_TICKET ? CMessage::Text(MSG_ORD_TICKET)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : " #"+(string)this.GetProperty(property) ) : property==ORDER_PROP_TICKET_FROM ? CMessage::Text(MSG_ORD_TICKET_FROM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : " #"+(string)this.GetProperty(property) ) : property==ORDER_PROP_TICKET_TO ? CMessage::Text(MSG_ORD_TICKET_TO)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : " #"+(string)this.GetProperty(property) ) : property==ORDER_PROP_TIME_EXP ? CMessage::Text(MSG_ORD_TIME_EXP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : (this.GetProperty(property)==0 ? CMessage::Text(MSG_LIB_PROP_NOT_SET) : ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS)) ) : property==ORDER_PROP_TYPE_FILLING ? CMessage::Text(MSG_ORD_TYPE_FILLING)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+OrderTypeFillingDescription((ENUM_ORDER_TYPE_FILLING)this.GetProperty(property)) ) : property==ORDER_PROP_TYPE_TIME ? CMessage::Text(MSG_ORD_TYPE_TIME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+OrderTypeTimeDescription((ENUM_ORDER_TYPE_TIME)this.GetProperty(property)) ) : property==ORDER_PROP_TYPE ? CMessage::Text(MSG_ORD_TYPE)+": "+this.TypeDescription() : property==ORDER_PROP_DIRECTION ? CMessage::Text(MSG_ORD_TYPE_BY_DIRECTION)+": "+this.DirectionDescription() : property==ORDER_PROP_REASON ? CMessage::Text(MSG_ORD_REASON)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetReasonDescription(this.GetProperty(property)) ) : property==ORDER_PROP_POSITION_ID ? CMessage::Text(MSG_ORD_POSITION_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": #"+(string)this.GetProperty(property) ) : property==ORDER_PROP_DEAL_ORDER_TICKET ? CMessage::Text(MSG_ORD_DEAL_ORDER_TICKET)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": #"+(string)this.GetProperty(property) ) : property==ORDER_PROP_DEAL_ENTRY ? CMessage::Text(MSG_ORD_DEAL_ENTRY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.GetEntryDescription(this.GetProperty(property)) ) : property==ORDER_PROP_POSITION_BY_ID ? CMessage::Text(MSG_ORD_POSITION_BY_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_TIME_OPEN ? CMessage::Text(MSG_ORD_TIME_OPEN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")" ) : property==ORDER_PROP_TIME_CLOSE ? CMessage::Text(MSG_ORD_TIME_CLOSE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")" ) : property==ORDER_PROP_TIME_UPDATE ? CMessage::Text(MSG_ORD_TIME_UPDATE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property)!=0 ?TimeMSCtoString(this.GetProperty(property))+" ("+(string)this.GetProperty(property)+")" : "0") ) : property==ORDER_PROP_STATE ? CMessage::Text(MSG_ORD_STATE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": \""+this.StateDescription()+"\"" ) : //--- 追加のプロパティ property==ORDER_PROP_STATUS ? CMessage::Text(MSG_ORD_STATUS)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": \""+this.StatusDescription()+"\"" ) : property==ORDER_PROP_PROFIT_PT ? ( this.Status()==ORDER_STATUS_MARKET_PENDING ? CMessage::Text(MSG_ORD_DISTANCE_PT) : CMessage::Text(MSG_ORD_PROFIT_PT) )+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_CLOSE_BY_SL ? CMessage::Text(MSG_LIB_PROP_CLOSE_BY_SL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==ORDER_PROP_CLOSE_BY_TP ? CMessage::Text(MSG_LIB_PROP_CLOSE_BY_TP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(this.GetProperty(property) ? CMessage::Text(MSG_LIB_TEXT_YES) : CMessage::Text(MSG_LIB_TEXT_NO)) ) : property==ORDER_PROP_MAGIC_ID ? CMessage::Text(MSG_ORD_MAGIC_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_GROUP_ID1 ? CMessage::Text(MSG_ORD_GROUP_ID1)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_GROUP_ID2 ? CMessage::Text(MSG_ORD_GROUP_ID2)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==ORDER_PROP_PEND_REQ_ID ? CMessage::Text(MSG_ORD_PEND_REQ_ID)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : "" ); } //+------------------------------------------------------------------+
メソッドの動作は抽象注文オブジェクトの作成に特化した最初の記事で検討したので、ここで説明する意味はありません。
前の記事では、保留中リクエストオブジェクトを使用して、ポジションを開くおよび指値注文を出すメソッドを実装しました。保留中リクエストを個々に識別するために、ポジションを開くまたは注文を出す際に、ポジションまたは注文のマジックナンバーに設定された一意のIDを使用しました。したがって、以前に作成された保留中リクエストの存在を特定し、ポジションがどのように開かれたかを見つけるのは簡単でした(一般的な取引リクエストまたは保留中リクエストオブジェクト操作の結果として)。これは、同じ取引アクションに対して複数の保留中リクエストオブジェクトを作成しないようにするために必要です。
ただし、取引は任意の注文やポジションを使って行うことができるため、ポジションの決済、注文の削除または変更を行う場合、IDは役に立ちません。それらはチケットによって実行されます。したがって、保留中リクエストが作成された注文/ポジションを理解するには、チケット番号が必要です。チケットは、保留中リクエストオブジェクトの取引リクエスト構造体に存在します。その値により、保留中リクエストが作成された注文またはポジションチケットを正確に定義できます。また、保留中リクエストの正常な処理を定義する必要があります。特に、正常に実行される前に、リクエストを使用して取引注文がサーバに送信された時期を定義する必要があります。次に、保留中取引リクエストが成功したかどうかを判断し、リクエストオブジェクトを削除して、前のリクエストが正常に完了した後の不要な取引試行を回避する必要があります。
このためにはすでに、口座内の取引イベントのクラスおよびこれらのイベントのコレクションクラスを用意しています。取引イベントコレクションクラスは、プログラムの開始以降に発生したすべてのイベントと、「今ここで」発生する現在のイベントへの完全なアクセスを既に提供しています。したがって、取引イベントコレクションクラスにアクセスするには、取引イベントコレクションクラスへのポインタを取引クラスに渡す必要があります。これを実現するには、クラスが自身を返すことができる必要があります。この機能を追加してみましょう。
GetObject() publicメソッドをEventsCollection.mqh取引イベントクラスファイルに追加します。
//+------------------------------------------------------------------+ //| Collection of account trading events | //+------------------------------------------------------------------+ class CEventsCollection : public CBaseObj { private: CListObj m_list_trade_events; // List of events bool m_is_hedge; // Hedge account flag int m_trade_event_code; // Trading event code ENUM_TRADE_EVENT m_trade_event; // Account trading event CEvent m_event_instance; // Event object for searching by property ulong m_position_id; // Position ID (MQL4) ENUM_ORDER_TYPE m_type_first; // Opening order type (MQL4) //--- Create a trading event depending on the (1) order status and (2) change type void CreateNewEvent(COrder* order,CArrayObj* list_history,CArrayObj* list_market,CArrayObj* list_control); void CreateNewEvent(COrderControl* order); //--- Create an event for a (1) hedging account, (2) netting account void NewDealEventHedge(COrder* deal,CArrayObj* list_history,CArrayObj* list_market); void NewDealEventNetto(COrder* deal,CArrayObj* list_history,CArrayObj* list_market); //--- Select and return the list of (1) market pending orders and (2) open positions CArrayObj* GetListMarketPendings(CArrayObj* list); CArrayObj* GetListPositions(CArrayObj* list); //--- Select and return the list of historical (1) closed positions, //--- (2) removed pending orders, (3) deals, (4) all closing orders CArrayObj* GetListHistoryPositions(CArrayObj* list); CArrayObj* GetListHistoryPendings(CArrayObj* list); CArrayObj* GetListDeals(CArrayObj* list); CArrayObj* GetListCloseByOrders(CArrayObj* list); //--- Return the list of (1) all position orders by its ID, (2) all deal positions by its ID //--- (3) all market entry deals by position ID, (4) all market exit deals by position ID, //--- (5) all position reversal deals by position ID CArrayObj* GetListAllOrdersByPosID(CArrayObj* list,const ulong position_id); CArrayObj* GetListAllDealsByPosID(CArrayObj* list,const ulong position_id); CArrayObj* GetListAllDealsInByPosID(CArrayObj* list,const ulong position_id); CArrayObj* GetListAllDealsOutByPosID(CArrayObj* list,const ulong position_id); CArrayObj* GetListAllDealsInOutByPosID(CArrayObj* list,const ulong position_id); //--- Return the total volume of all deals (1) IN, (2) OUT of the position by its ID double SummaryVolumeDealsInByPosID(CArrayObj* list,const ulong position_id); double SummaryVolumeDealsOutByPosID(CArrayObj* list,const ulong position_id); //--- Return the (1) first, (2) last and (3) closing order from the list of all position orders, //--- (4) an order by ticket, (5) market position by ID, //--- (6) the last and (7) penultimate InOut deal by position ID COrder* GetFirstOrderFromList(CArrayObj* list,const ulong position_id); COrder* GetLastOrderFromList(CArrayObj* list,const ulong position_id); COrder* GetCloseByOrderFromList(CArrayObj* list,const ulong position_id); COrder* GetHistoryOrderByTicket(CArrayObj* list,const ulong order_ticket); COrder* GetPositionByID(CArrayObj* list,const ulong position_id); //--- Return (1) the control order by a ticket, (2) the type of the opening order by the position ticket (MQL4) COrderControl* GetOrderControlByTicket(CArrayObj* list,const ulong ticket); ENUM_ORDER_TYPE GetTypeFirst(CArrayObj* list,const ulong ticket); //--- Return the flag of the event object presence in the event list bool IsPresentEventInList(CEvent* compared_event); //--- The handler of an existing order/position change event void OnChangeEvent(CArrayObj* list_changes,const int index); public: //--- Return itself CEventsCollection*GetObject(void) { return &this; } //--- Select events from the collection with time within the range from begin_time to end_time CArrayObj *GetListByTime(const datetime begin_time=0,const datetime end_time=0); //--- Return the full event collection list "as is" CArrayObj *GetList(void) { return &this.m_list_trade_events; } //--- 比較された基準を満たす選択された(1)整数、(2)実数、(3)文字列プロパティののリストを返す CArrayObj *GetList(ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByEventProperty(this.GetList(),property,value,mode); } //--- Update the list of events void Refresh(CArrayObj* list_history, CArrayObj* list_market, CArrayObj* list_changes, CArrayObj* list_control, const bool is_history_event, const bool is_market_event, const int new_history_orders, const int new_market_pendings, const int new_market_positions, const int new_deals, const double changed_volume); //--- Return (1) the last trading event on an account, (2) base event object by index and (3) number of new events ENUM_TRADE_EVENT GetLastTradeEvent(void) const { return this.m_trade_event; } CEventBaseObj *GetTradeEventByIndex(const int index) { return this.GetEvent(index,false); } int GetTradeEventsTotal(void) const { return this.m_list_events.Total(); } //--- 直近の取引イベントをリセットする void ResetLastTradeEvent(void) { this.m_trade_event=TRADE_EVENT_NO_EVENT; } //--- コンストラクタ CEventsCollection(void); }; //+------------------------------------------------------------------+
これでCEventsCollectionクラスは自らへのポインタを返すことができます。これは、後で必要になります。
基本取引クラスの取引メソッドコードに関していくつかの最適化が行われたことはすでに述べました。ポジションを開くメソッドを例としてとります。この変更は主に、取引注文をサーバに送信するブロックに影響しました。
次は以前のコードです。
//+------------------------------------------------------------------+ //| 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 string comment=NULL, const ulong deviation=ULONG_MAX, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE) { ::ResetLastError(); //--- 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 = (ENUM_ORDER_TYPE)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 #ifdef __MQL5__ return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)); #else ::ResetLastError(); int ticket=::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); ::SymbolInfoTick(this.m_symbol,this.m_tick); if(ticket!=WRONG_VALUE) { this.m_result.retcode=::GetLastError(); this.m_result.ask=this.m_tick.ask; this.m_result.bid=this.m_tick.bid; this.m_result.deal=ticket; this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price); this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume); this.m_result.comment=CMessage::Text(this.m_result.retcode); return true; } else { this.m_result.retcode=::GetLastError(); this.m_result.ask=this.m_tick.ask; this.m_result.bid=this.m_tick.bid; this.m_result.comment=CMessage::Text(this.m_result.retcode); return false; } #endif } //+------------------------------------------------------------------+
よく見ると、多くのコードの反復が見られます。それらはすべて、チケット検証ブロックの外側に配置されています。また、MQL4で最後のエラーコードをリセットする際には論理エラーがありました。リセットはサーバに取引リクエストを送信する前に発生し、価格受信関数(それ自体もエラーを返すこともあります)がエラーコードを受信する前に設定されていました。この場合、最後のエラーコードはMQL4の取引サーバの戻りコードに属していません。
上記のすべてを考慮すると、ポジションを開くメソッドで取引注文をサーバに送信するブロックは次のようになります。
//+------------------------------------------------------------------+ //| 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 string comment=NULL, const ulong deviation=ULONG_MAX, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE) { ::ResetLastError(); //--- 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 = (ENUM_ORDER_TYPE)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 #ifdef __MQL5__ return(!this.m_async_mode ? ::OrderSend(this.m_request,this.m_result) : ::OrderSendAsync(this.m_request,this.m_result)); #else ::ResetLastError(); int ticket=::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); this.m_result.retcode=::GetLastError(); ::SymbolInfoTick(this.m_symbol,this.m_tick); this.m_result.ask=this.m_tick.ask; this.m_result.bid=this.m_tick.bid; this.m_result.comment=CMessage::Text(this.m_result.retcode); if(ticket!=WRONG_VALUE) { this.m_result.deal=ticket; this.m_result.price=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderOpenPrice() : this.m_request.price); this.m_result.volume=(::OrderSelect(ticket,SELECT_BY_TICKET) ? ::OrderLots() : this.m_request.volume); return true; } else { return false; } #endif } //+------------------------------------------------------------------+
残りのクラス取引メソッドはすべて、各メソッドの詳細に応じたわずかな違いを除いて、同じように改善されています。
以下に添付されているコードですべての変更を確認できます。
次に、保留中リクエストを処理してポジション決済/注文削除を行い、ポジションと注文パラメータを変更するメソッドの開発を始めましょう。
ポジションと指値注文を決済/削除/変更する保留中リクエスト
Trading.mqh基本取引クラスファイルで、口座取引イベントコレクションのクラスを含めます。
//+------------------------------------------------------------------+ //| Trading.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 <Arrays\ArrayInt.mqh> #include "Objects\Trade\TradeObj.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\EventsCollection.mqh" //+------------------------------------------------------------------+
リストが同じファイルにあるCPendingReq保留中リクエストクラスに、注文チケット、ポジションチケット、および取引操作タイプを返すメソッドを追加します。
//+------------------------------------------------------------------+ //| Pending request object class | //+------------------------------------------------------------------+ class CPendingReq : public CObject { private: MqlTradeRequest m_request; // Trade request structure uchar m_id; // Trading request ID int m_type; // Pending request type int m_retcode; // Result a request is based on double m_price_create; // Price at the moment of a request generation ulong m_time_create; // Request generation time ulong m_time_activate; // Next attempt activation time ulong m_waiting_msc; // Waiting time between requests uchar m_current_attempt; // Current attempt index uchar m_total_attempts; // Number of attempts //--- Copy trading request data void CopyRequest(const MqlTradeRequest &request) { this.m_request=request; } //--- Compare CPendingReq objects by IDs virtual int Compare(const CObject *node,const int mode=0) const; public: //--- Return (1) the request structure, (2) the price at the moment of the request generation, //--- (3) request generation time, (4) next attempt activation time, //--- (5) waiting time between requests, (6) current attempt index, //--- (7) number of attempts, (8) request ID //--- (9) result a request is based on, //--- (10) order ticket, (11) position ticket, (12) trading operation type MqlTradeRequest MqlRequest(void) const { return this.m_request; } double PriceCreate(void) const { return this.m_price_create; } ulong TimeCreate(void) const { return this.m_time_create; } ulong TimeActivate(void) const { return this.m_time_activate; } ulong WaitingMSC(void) const { return this.m_waiting_msc; } uchar CurrentAttempt(void) const { return this.m_current_attempt; } uchar TotalAttempts(void) const { return this.m_total_attempts; } uchar ID(void) const { return this.m_id; } int Retcode(void) const { return this.m_retcode; } ulong Order(void) const { return this.m_request.order; } ulong Position(void) const { return this.m_request.position;} ENUM_TRADE_REQUEST_ACTIONS Action(void) const { return this.m_request.action; }
また、注文を出すメソッドとポジションチケットを設定するメソッドを追加します。
//--- Set (1) the price when creating a request, (2) request creation time, //--- (3) current attempt time, (4) waiting time between requests, //--- (5) current attempt index, (6) number of attempts, (7) ID, //--- (8) order ticket, (9) position ticket void SetPriceCreate(const double price) { this.m_price_create=price; } void SetTimeCreate(const ulong time) { this.m_time_create=time; } void SetTimeActivate(const ulong time) { this.m_time_activate=time; } void SetWaitingMSC(const ulong miliseconds) { this.m_waiting_msc=miliseconds;} void SetCurrentAttempt(const uchar number) { this.m_current_attempt=number; } void SetTotalAttempts(const uchar number) { this.m_total_attempts=number; } void SetID(const uchar id) { this.m_id=id; } void SetOrder(const ulong ticket) { this.m_request.order=ticket; } void SetPosition(const ulong ticket) { this.m_request.position=ticket;}
指定されたプロパティによってCPendingReqクラスオブジェクトを比較するCompare()メソッドが変更されました。
次は以前のコードです。
//+------------------------------------------------------------------+ //| Compare CPendingReq objects by properties | //+------------------------------------------------------------------+ int CPendingReq::Compare(const CObject *node,const int mode=0) const { const CPendingReq *compared_req=node; return ( //--- Compare by ID mode==0 ? (this.ID()>compared_req.ID() ? 1 : this.ID()<compared_req.ID() ? -1 : 0) : //--- Compare by type (this.Type()>compared_req.Type() ? 1 : this.Type()<compared_req.Type() ? -1 : 0) ); } //+------------------------------------------------------------------+
つまり、2つの保留中のリクエストオブジェクトプロパティによってのみ比較が実行されています。
3番目ができたので、メソッドは次のようになります。
//+------------------------------------------------------------------+ //| Compare CPendingReq objects by properties | //+------------------------------------------------------------------+ int CPendingReq::Compare(const CObject *node,const int mode=0) const { const CPendingReq *compared_req=node; return ( //--- Compare by ID mode==SORT_BY_PEND_REQ_ID ? (this.ID()>compared_req.ID() ? 1 : this.ID()<compared_req.ID() ? -1 : 0) : //--- Compare by type mode==SORT_BY_PEND_REQ_TYPE ? (this.Type()>compared_req.Type() ? 1 : this.Type()<compared_req.Type() ? -1 : 0) : //--- Compare by ticket ( //--- modifying position sl, tp, opening/closing a position or closing by an opposite one this.m_request.action==TRADE_ACTION_SLTP || this.m_request.action==TRADE_ACTION_DEAL || this.m_request.action==TRADE_ACTION_CLOSE_BY ? (this.m_request.position>compared_req.m_request.position ? 1 : this.m_request.position<compared_req.m_request.position ? -1 : 0) : //--- modifying parameters, placing/removing a pending order this.m_request.action==TRADE_ACTION_MODIFY || this.m_request.action==TRADE_ACTION_PENDING || this.m_request.action==TRADE_ACTION_REMOVE ? (this.m_request.order>compared_req.m_request.order ? 1 : this.m_request.order<compared_req.m_request.order ? -1 : 0) : //--- otherwise 0 ) ); } //+------------------------------------------------------------------+
- メソッドに渡された比較モードが、ENUM_SORT_PEND_REQ_MODE列挙からのSORT_BY_PEND_REQ_ID定数値と等しい場合、保留中リクエストオブジェクトIDによって比較が実行されます。
- 比較モードがSORT_BY_PEND_REQ_TYPEの場合、比較は保留中リクエストオブジェクトタイプによって実行されます。
- 3番目の比較モード(SORT_BY_PEND_REQ_TICKET)は次のように機能します。
- 取引操作タイプを確認し、 - これがポジションストップ注文の変更、ポジションの開始と決済、または反対のポジションによる決済の場合、比較はポジションチケットを格納する取引リクエスト構造体のpositionフィールドの値によって実行されます。
- これがパラメータの変更、指値注文の配置または削除である場合、比較は注文チケットを保存する取引リクエスト構造体のorderフィールドの値によって実行されます。
- その他の場合は、ゼロが返されます。
CTrading取引クラスのprivateセクションで、口座取引イベントのコレクションクラスへのポインタを宣言します。
//+------------------------------------------------------------------+ //| Trading class | //+------------------------------------------------------------------+ class CTrading { private: CAccount *m_account; // Pointer to the current account object CSymbolsCollection *m_symbols; // Pointer to the symbol collection list CMarketCollection *m_market; // Pointer to the list of the collection of market orders and positions CHistoryCollection *m_history; // Pointer to the list of the collection of historical orders and deals CEventsCollection *m_events; // Pointer to the event collection list CArrayObj m_list_request; // List of pending requests CArrayInt m_list_errors; // Error list bool m_is_trade_disable; // Flag disabling trading bool m_use_sound; // The flag of using sounds of the object trading events uchar m_total_try; // Number of trading attempts ENUM_LOG_LEVEL m_log_level; // Logging level MqlTradeRequest m_request; // Trading request prices ENUM_TRADE_REQUEST_ERR_FLAGS m_error_reason_flags; // Flags of error source in a trading method ENUM_ERROR_HANDLING_BEHAVIOR m_err_handling_behavior; // Behavior when handling error
同じセクションで、注文チケットとポジションチケットによって保留中リクエストオブジェクトインデックスを返すメソッドを宣言します。
//--- Return the request object index in the list by (1) ID, //--- (2) order ticket, (3) position ticket in the request int GetIndexPendingRequestByID(const uchar id); int GetIndexPendingRequestByOrder(const ulong ticket); int GetIndexPendingRequestByPosition(const ulong ticket); public:
クラス本体の外側で実装しましょう。
//+------------------------------------------------------------------+ //| Return the request object index in the list by the order ticket | //+------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByOrder(const ulong ticket) { CPendingReq *req=new CPendingReq(); if(req==NULL) return WRONG_VALUE; req.SetOrder(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_TICKET); int index=this.m_list_request.Search(req); delete req; return index; } //+-------------------------------------------------------------------+ //| Return the request object index in the list by the position ticket| //+-------------------------------------------------------------------+ int CTrading::GetIndexPendingRequestByPosition(const ulong ticket) { CPendingReq *req=new CPendingReq(); if(req==NULL) return WRONG_VALUE; req.SetPosition(ticket); this.m_list_request.Sort(SORT_BY_PEND_REQ_TICKET); int index=this.m_list_request.Search(req); delete req; return index; } //+------------------------------------------------------------------+
IDによってリクエストオブジェクトインデックスを返すための同様のメソッドは前の記事ですでに検討したので、操作の原則を理解するには、その説明を読み直してください。現在のメソッドはまったく同じです。
クラスのpublicセクションで、クラス初期化メソッドを補足し、必要なすべてのコレクションリストへのポインタを取引クラスに渡すようにします。
取引イベントコレクションへのポインタを渡しポインタをm_events変数値に書き込むようにします。
public: //--- コンストラクタ CTrading(); //--- タイマー void OnTimer(void); //--- Get the pointers to the lists (make sure to call the method in program's OnInit() since the symbol collection list is created there) void OnInit(CAccount *account,CSymbolsCollection *symbols,CMarketCollection *market,CHistoryCollection *history,CEventsCollection *events) { this.m_account=account; this.m_symbols=symbols; this.m_market=market; this.m_history=history; this.m_events=events; }
注文チケットまたはポジションチケットを制限とエラーを確認するメソッドに渡すようにします。
//--- Check limitations and errors ENUM_ERROR_CODE_PROCESSING_METHOD CheckErrors(const double volume, const double price, const ENUM_ACTION_TYPE action, const ENUM_ORDER_TYPE order_type, CSymbol *symbol_obj, CTradeObj *trade_obj, const string source_method, const double limit=0, double sl=0, double tp=0, ulong ticket=0);
チケットを使用すると、メソッドに、そのチケットを持つ注文またはポジションの以前に作成された保留中リクエストオブジェクトが含まれるかどうかを定義できます。これは、操作ログで同じエラーに関する同じメッセージを表示しないようにするために行われます。言い換えると、サーバが初めてエラーを返したときに、操作ログにエラーメッセージを表示し、保留中リクエストを作成して、取引メソッドを終了します。エラーが繰り返し発生する場合は、そのチケットを持つ注文またはポジションに対して以前に作成された保留中リクエストオブジェクトが存在するかどうかを確認します。存在する場合、エラーメッセージは既に表示されているので、繰り返しても意味がありません。
改善されたメソッドの実装を見てみましょう。
//+------------------------------------------------------------------+ //| Check limitations and errors | //+------------------------------------------------------------------+ ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::CheckErrors(const double volume, const double price, const ENUM_ACTION_TYPE action, const ENUM_ORDER_TYPE order_type, CSymbol *symbol_obj, CTradeObj *trade_obj, const string source_method, const double limit=0, double sl=0, double tp=0, ulong ticket=0) { //--- Check the previously set flag disabling trading for an EA if(this.IsTradingDisable()) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_FATAL_ERROR; this.AddErrorCodeToList(MSG_LIB_TEXT_TRADING_DISABLE); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(source_method,CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); return ERROR_CODE_PROCESSING_METHOD_DISABLE; } //--- result of all checks and error flags this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; bool res=true; //--- Clear the error list this.m_list_errors.Clear(); this.m_list_errors.Sort(); //--- Check trading limitations res &=this.CheckTradeConstraints(volume,action,symbol_obj,source_method,sl,tp); //--- Check the funds sufficiency for opening positions/placing orders if(action<ACTION_TYPE_CLOSE_BY) res &=this.CheckMoneyFree(volume,price,order_type,symbol_obj,source_method); //--- Check parameter values by StopLevel and FreezeLevel res &=this.CheckLevels(action,order_type,price,limit,sl,tp,symbol_obj,source_method); //--- If there are limitations and errors, display the header and the error list if(!res) { //--- Declare the pending request index int index=WRONG_VALUE; //--- Request was rejected before sending to the server due to: int total=this.m_list_errors.Total(); if(this.m_log_level>LOG_LEVEL_NO_MSG) { //--- in case of closing by an opposite position or opening/closing a position, the index is received by the position ticket if(action==ACTION_TYPE_CLOSE_BY || action<ACTION_TYPE_BUY_LIMIT) index=this.GetIndexPendingRequestByPosition(ticket); //--- if a trading operation is closing a position, removing an order or modifying it... else if(action>ACTION_TYPE_CLOSE_BY) { //--- if this is a position, receive the index by a position ticket if(order_type<ORDER_TYPE_BUY_LIMIT) index=this.GetIndexPendingRequestByPosition(ticket); //--- otherwise, receive the index by an order ticket else index=this.GetIndexPendingRequestByOrder(ticket); } //--- otherwise, if a trading operation is placing a pending order, receive the index by an order ticket else index=this.GetIndexPendingRequestByOrder(ticket); //--- if no index is received, there is no such pending request object, display the error message if(index==WRONG_VALUE) { //--- For MQL5, first display the list header followed by the error list #ifdef __MQL5__ ::Print(source_method,CMessage::Text(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK ? MSG_LIB_TEXT_REQUEST_REJECTED_DUE : MSG_LIB_TEXT_INVALID_REQUEST)); for(int i=0;i<total;i++) ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i))); //--- For MQL4, the journal messages are displayed in the reverse order: the error list in the reverse loop is followed by the list header #else for(int i=total-1;i>WRONG_VALUE;i--) ::Print((total>1 ? string(i+1)+". " : ""),CMessage::Text(m_list_errors.At(i))); ::Print(source_method,CMessage::Text(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK ? MSG_LIB_TEXT_REQUEST_REJECTED_DUE : MSG_LIB_TEXT_INVALID_REQUEST)); #endif } } //--- If the action is performed at the "abort trading operation" error if(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_BREAK) return ERROR_CODE_PROCESSING_METHOD_EXIT; //--- If the action is performed at the "correct parameters" error if(this.m_err_handling_behavior==ERROR_HANDLING_BEHAVIOR_CORRECT) { if(this.m_log_level>LOG_LEVEL_NO_MSG && index==WRONG_VALUE) ::Print(CMessage::Text(MSG_LIB_TEXT_CORRECTED_TRADE_REQUEST)); //--- Return the result of an attempt to correct the request parameters return this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); } } //--- No limitations and errors trade_obj.SetResultRetcode(0); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_OK; } //+------------------------------------------------------------------+
ロジック全体は、コードのコメントで提供されており、コメントですべてが明確であることを願っています。
保留中取引リクエストの処理がクラスタイマーに実装されました。
非常に多くの変更を行ったため、コードコメントで操作ロジック全体を説明するために最善を尽くしました。
//+------------------------------------------------------------------+ //| Timer | //+------------------------------------------------------------------+ void CTrading::OnTimer(void) { //--- In a loop by the list of pending requests int total=this.m_list_request.Total(); for(int i=total-1;i>WRONG_VALUE;i--) { //--- receive the next request object CPendingReq *req_obj=this.m_list_request.At(i); if(req_obj==NULL) continue; //--- get the request structure and the symbol object a trading operation should be performed for MqlTradeRequest request=req_obj.MqlRequest(); CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(request.symbol); if(symbol_obj==NULL || !symbol_obj.RefreshRates()) continue; //--- if the current attempt exceeds the defined number of trading attempts, //--- or the current time exceeds the waiting time of all attempts //--- remove the current request object and move on to the next one if(req_obj.CurrentAttempt()>req_obj.TotalAttempts() || req_obj.CurrentAttempt()>=UCHAR_MAX || (long)symbol_obj.Time()>long(req_obj.TimeCreate()+req_obj.WaitingMSC()*req_obj.TotalAttempts())) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); continue; } //--- If this is a position opening or placing a pending order if((req_obj.Action()==TRADE_ACTION_DEAL && req_obj.Position()==0) || req_obj.Action()==TRADE_ACTION_PENDING) { //--- Get the pending request ID uchar id=this.GetPendReqID((uint)request.magic); //--- Get the list of orders/positions containing the order/position with the pending request ID CArrayObj *list=this.m_market.GetList(ORDER_PROP_PEND_REQ_ID,id,EQUAL); if(::CheckPointer(list)==POINTER_INVALID) continue; //--- If the order/position is present, the request is handled: remove it and proceed to the next if(list.Total()>0) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); continue; } } //--- Otherwise: full and partial position closure, removing an order, modifying order parameters and position stop orders else { CArrayObj *list=NULL; //--- if this is a position closure, including a closure by an opposite one if((req_obj.Action()==TRADE_ACTION_DEAL && req_obj.Position()>0) || req_obj.Action()==TRADE_ACTION_CLOSE_BY) { //--- Get a position with the necessary ticket from the list of open positions list=this.m_market.GetList(ORDER_PROP_TICKET,req_obj.Position(),EQUAL); if(::CheckPointer(list)==POINTER_INVALID) continue; //--- If the market has no such position - the request is handled: remove it and proceed to the next one if(list.Total()==0) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); continue; } //--- Otherwise, if the position still exists, this is a partial closure else { //--- Get the list of all account trading events list=this.m_events.GetList(); if(list==NULL) continue; //--- In the loop from the end of the account trading event list int events_total=list.Total(); for(int j=events_total-1; j>WRONG_VALUE; j--) { //--- get the next trading event CEvent *event=list.At(j); if(event==NULL) continue; //--- If this event is a partial closure or there was a partial closure when closing by an opposite one if(event.TypeEvent()==TRADE_EVENT_POSITION_CLOSED_PARTIAL || event.TypeEvent()==TRADE_EVENT_POSITION_CLOSED_PARTIAL_BY_POS) { //--- If a position ticket in a trading event coincides with the ticket in a pending trading request - //--- the request is handled: remove it and break the loop by the list of account trading events if(event.TicketFirstOrderPosition()==req_obj.Position()) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); break; } } } //--- If a handled pending request object was removed by the trading event list in the loop, move on to the next one if(::CheckPointer(req_obj)==POINTER_INVALID) continue; } } //--- If this is a modification of position stop orders if(req_obj.Action()==TRADE_ACTION_SLTP) { //--- Get the list of all account trading events list=this.m_events.GetList(); if(list==NULL) continue; //--- In the loop from the end of the account trading event list int events_total=list.Total(); for(int j=events_total-1; j>WRONG_VALUE; j--) { //--- get the next trading event CEvent *event=list.At(j); if(event==NULL) continue; //--- If this is a change of the position's stop orders if(event.TypeEvent()>TRADE_EVENT_MODIFY_ORDER_TAKE_PROFIT) { //--- If a position ticket in a trading event coincides with the ticket in a pending trading request - //--- the request is handled: remove it and break the loop by the list of account trading events if(event.TicketFirstOrderPosition()==req_obj.Position()) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); break; } } } //--- If a handled pending request object was removed by the trading event list in the loop, move on to the next one if(::CheckPointer(req_obj)==POINTER_INVALID) continue; } //--- If this is a pending order removal if(req_obj.Action()==TRADE_ACTION_REMOVE) { //--- Get the list of removed pending orders list=this.m_history.GetList(ORDER_PROP_STATUS,ORDER_STATUS_HISTORY_PENDING,EQUAL); if(::CheckPointer(list)==POINTER_INVALID) continue; //--- Leave a single order with the necessary ticket in the list list=CSelect::ByOrderProperty(list,ORDER_PROP_TICKET,req_obj.Order(),EQUAL); //--- If the order is present, the request is handled: remove it and proceed to the next if(list.Total()>0) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); continue; } } //--- If this is a pending order modification if(req_obj.Action()==TRADE_ACTION_MODIFY) { //--- Get the list of all account trading events list=this.m_events.GetList(); if(list==NULL) continue; //--- In the loop from the end of the account trading event list int events_total=list.Total(); for(int j=events_total-1; j>WRONG_VALUE; j--) { //--- get the next trading event CEvent *event=list.At(j); if(event==NULL) continue; //--- If this event involves any change of modified pending order parameters if(event.TypeEvent()>TRADE_EVENT_TRIGGERED_STOP_LIMIT_ORDER && event.TypeEvent()<TRADE_EVENT_MODIFY_POSITION_STOP_LOSS_TAKE_PROFIT) { //--- If an order ticket in a trading event coincides with the ticket in a pending trading request - //--- the request is handled: remove it and break the loop by the list of account trading events if(event.TicketOrderEvent()==req_obj.Order()) { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(req_obj.IdDescription(),": ",CMessage::Text(MSG_LIB_TEXT_PEND_REQUEST_EXECUTED)); this.m_list_request.Delete(i); break; } } } } } //--- Exit if the pending request object has been removed after checking its operation if(::CheckPointer(req_obj)==POINTER_INVALID) return; //--- Set the request activation time in the request object req_obj.SetTimeActivate(req_obj.TimeCreate()+req_obj.WaitingMSC()*(req_obj.CurrentAttempt()+1)); //--- If the current time is less than the request activation time, //--- this is not the request time - move on to the next request in the list if((long)symbol_obj.Time()<(long)req_obj.TimeActivate()) continue; //--- Set the attempt number in the request object req_obj.SetCurrentAttempt(uchar(req_obj.CurrentAttempt()+1)); //--- Display the number of a trading attempt in the journal if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_RE_TRY_N)+(string)req_obj.CurrentAttempt()); //--- Depending on the type of action performed in the trading request switch(request.action) { //--- Opening/closing a position case TRADE_ACTION_DEAL : //--- If no ticket is present in the request structure - this is opening a position if(request.position==0) this.OpenPosition((ENUM_POSITION_TYPE)request.type,request.volume,request.symbol,request.magic,request.sl,request.tp,request.comment,request.deviation,request.type_filling); //--- If the ticket is present in the request structure - this is a position closure else this.ClosePosition(request.position,request.volume,request.comment,request.deviation); break; //--- Modify StopLoss/TakeProfit position case TRADE_ACTION_SLTP : this.ModifyPosition(request.position,request.sl,request.tp); break; //--- Close by an opposite one case TRADE_ACTION_CLOSE_BY : this.ClosePositionBy(request.position,request.position_by); break; //--- //--- Place a pending order case TRADE_ACTION_PENDING : this.PlaceOrder(request.type,request.volume,request.symbol,request.price,request.stoplimit,request.sl,request.tp,request.magic,request.comment,request.expiration,request.type_time,request.type_filling); break; //--- Modify a pending order case TRADE_ACTION_MODIFY : this.ModifyOrder(request.order,request.price,request.sl,request.tp,request.stoplimit,request.expiration,request.type_time,request.type_filling); break; //--- Remove a pending order case TRADE_ACTION_REMOVE : Print(DFUN,RequestActionDescription(req_obj.MqlRequest())); this.DeleteOrder(request.order); break; //--- default: break; } } } //+------------------------------------------------------------------+
ここでは、すべての取引イベントのリストが必要です。保留中リクエストのアクティブ化を定義して削除するためです。そうしないと、保留中リクエストは、割り当てられたすべての取引試行を使用した後にのみ削除されます。例えば、ポジションの部分決済の場合、そのような保留中リクエストは、ポジション全体が完全に決済されるか、すべての取引試行が使用されるまで、ポジションの一部を徐々に決済します。これは間違っており、修正する必要があります。したがって、発生した取引イベントを定義し、保留中取引リクエストオブジェクトと比較します。一致する場合は、このオブジェクトを実行済みとして削除し、操作ログで通知します。
エラーの処理方法を返すメソッドで、端末側からの取引許可がないことのエラーを、待機を返すブロックに移動します。
//+------------------------------------------------------------------+ //| Return the error handling method | //+------------------------------------------------------------------+ ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::ResultProccessingMethod(const uint result_code) { switch(result_code) { #ifdef __MQL4__ //--- Malfunctional trade operation case 9 : //--- Account disabled case 64 : //--- Invalid account number case 65 : return ERROR_CODE_PROCESSING_METHOD_DISABLE; //--- No error but result is unknown case 1 : //--- General error case 2 : //--- Old client terminal version case 5 : //--- Not enough rights case 7 : //--- Market closed case 132 : //--- Trading disabled case 133 : //--- Order is locked and being processed case 139 : //--- Buy only case 140 : //--- The number of open and pending orders has reached the limit set by the broker case 148 : //--- Attempt to open an opposite order if hedging is disabled case 149 : //--- Attempt to close a position on a symbol contradicts the FIFO rule case 150 : return ERROR_CODE_PROCESSING_METHOD_EXIT; //--- Invalid trading request parameters case 3 : //--- Invalid price case 129 : //--- Invalid stop levels case 130 : //--- Invalid volume case 131 : //--- Not enough money to perform the operation case 134 : //--- Expirations are denied by broker case 147 : return ERROR_CODE_PROCESSING_METHOD_CORRECT; //--- Trade server is busy case 4 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds //--- No connection to the trade server case 6 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds //--- Too frequent requests case 8 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds //--- No price case 136 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds //--- Broker is busy case 137 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)15000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 15 seconds //--- Too many requests case 141 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds //--- Modification denied because the order is too close to market case 145 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds //--- Trade context is busy case 146 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds //--- Trade timeout case 128 : //--- Price has changed case 135 : //--- New prices case 138 : return ERROR_CODE_PROCESSING_METHOD_REFRESH; //--- MQL5 #else //--- Auto trading disabled by the server case 10026 : return ERROR_CODE_PROCESSING_METHOD_DISABLE; //--- Request canceled by a trader case 10007 : //--- Request handling error case 10011 : //--- Request expired case 10012 : //--- Trading disabled case 10017 : //--- Market closed case 10018 : //--- Order status changed case 10023 : //--- Request unchanged case 10025 : //--- Request blocked for handling case 10028 : //--- Transaction is allowed for live accounts only case 10032 : //--- The maximum number of pending orders is reached case 10033 : //--- Reached the maximum order and position volume for this symbol case 10034 : //--- Invalid or prohibited order type case 10035 : //--- Position with the specified ID already closed case 10036 : //--- A close order is already present for a specified position case 10039 : //--- The maximum number of open positions is reached case 10040 : //--- Request to activate a pending order is rejected, the order is canceled case 10041 : //--- Request is rejected, because the rule "Only long positions are allowed" is set for the symbol case 10042 : //--- Request is rejected, because the rule "Only short positions are allowed" is set for the symbol case 10043 : //--- Request is rejected, because the rule "Only closing of existing positions is allowed" is set for the symbol case 10044 : //--- Request is rejected, because the rule "Only closing of existing positions by FIFO rule is allowed" is set for the symbol case 10045 : return ERROR_CODE_PROCESSING_METHOD_EXIT; //--- Requote case 10004 : //--- Prices changed case 10020 : return ERROR_CODE_PROCESSING_METHOD_REFRESH; //--- Invalid request case 10013 : //--- Invalid request volume case 10014 : //--- Invalid request price case 10015 : //--- Invalid request stop levels case 10016 : //--- Insufficient funds for request execution case 10019 : //--- Invalid order expiration in a request case 10022 : //--- The specified type of order execution by balance is not supported case 10030 : //--- Closed volume exceeds the current position volume case 10038 : return ERROR_CODE_PROCESSING_METHOD_CORRECT; //--- Request rejected case 10006 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)15000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 15 seconds //--- No quotes to handle the request case 10021 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 5 seconds //--- Too frequent requests case 10024 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds //--- Auto trading disabled by the client terminal case 10027 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds //--- An order or a position is frozen case 10029 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)10000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 10 seconds //--- No connection to the trade server case 10031 : return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000; // ERROR_CODE_PROCESSING_METHOD_WAIT; Wait 20 seconds //--- Order placed case 10008 : //--- Request executed case 10009 : //--- Request executed partially case 10010 : #endif //--- "OK" default: break; } return ERROR_CODE_PROCESSING_METHOD_OK; } //+------------------------------------------------------------------+
したがって、端末の自動取引ボタンを無効にして取引リクエストを送信しようとすると、保留中リクエストが生成されます。自動取引ボタンを有効にしたら、保留中リクエストをアクティブにする必要があります。実際、このようなエラーは、自動取引のアクティベーションを待つことで処理する必要がありますが、すべての取引試行に割り当てられた合計待ち時間がまだ使い切っていない場合のみです。
エラー修正メソッドでは、「取引メソッドを終了」コードを使用して、メソッドから返されたコードブロックを削除します。
//+------------------------------------------------------------------+ //| Correct errors | //+------------------------------------------------------------------+ ENUM_ERROR_CODE_PROCESSING_METHOD CTrading::RequestErrorsCorrecting(MqlTradeRequest &request, const ENUM_ORDER_TYPE order_type, const uint spread_multiplier, CSymbol *symbol_obj, CTradeObj *trade_obj) { //--- The empty error list means no errors are detected, return success int total=this.m_list_errors.Total(); if(total==0) return ERROR_CODE_PROCESSING_METHOD_OK; //--- Trading is disabled for the current account //--- write the error code to the base trading class object and return "exit from the trading method" if(this.IsPresentErorCode(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED)) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_ACCOUNT_NOT_TRADE_ENABLED); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_EXIT; } //--- Trading on the trading server side is disabled for EAs on the current account //--- write the error code to the base trading class object and return "exit from the trading method" if(this.IsPresentErorCode(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED)) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_ACCOUNT_EA_NOT_TRADE_ENABLED); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_EXIT; } //--- Trading operations are disabled in the terminal //--- write the error code to the base trading class object and return "exit from the trading method" if(this.IsPresentErorCode(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED)) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_EXIT; } //--- Trading operations are disabled for the EA //--- write the error code to the base trading class object and return "exit from the trading method" if(this.IsPresentErorCode(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED)) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_EXIT; } //--- Disable trading on a symbol
検出されたエラーのリストを処理するブロックで、端末またはEAで取引が無効になっている場合は、メソッドから20秒待機を戻すコードを追加します。
//--- View the list of remaining errors and correct trading request parameters for(int i=0;i<total;i++) { int err=this.m_list_errors.At(i); if(err==NULL) continue; switch(err) { //--- Correct an invalid volume and disabling stop levels in a trading request case MSG_LIB_TEXT_REQ_VOL_LESS_MIN_VOLUME : case MSG_LIB_TEXT_REQ_VOL_MORE_MAX_VOLUME : case MSG_LIB_TEXT_INVALID_VOLUME_STEP : request.volume=symbol_obj.NormalizedLot(request.volume); break; case MSG_SYM_SL_ORDER_DISABLED : request.sl=0; break; case MSG_SYM_TP_ORDER_DISABLED : request.tp=0; break; //--- If unable to select the position lot, return "abort trading attempt" since the funds are insufficient even for the minimum lot case MSG_LIB_TEXT_NOT_ENOUTH_MONEY_FOR : request.volume=this.CorrectVolume(request.price,order_type,symbol_obj,DFUN); if(request.volume==0) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_NOT_POSSIBILITY_CORRECT_LOT); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_EXIT; break; } //--- No quotes to handle the request case 10021 : trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 5 seconds //--- No connection to the trade server case 10031 : trade_obj.SetResultRetcode(10031); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000; // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 20 seconds //--- Proximity to the order activation level is handled by five-second waiting - during this time, the price may go beyond the freeze level case MSG_LIB_TEXT_SL_LESS_FREEZE_LEVEL : case MSG_LIB_TEXT_TP_LESS_FREEZE_LEVEL : case MSG_LIB_TEXT_PR_LESS_FREEZE_LEVEL : return (ENUM_ERROR_CODE_PROCESSING_METHOD)5000; // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 5 seconds //--- Trading operations are disabled in the terminal case MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED : //--- Trading operations are disabled for the EA case MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED : return (ENUM_ERROR_CODE_PROCESSING_METHOD)20000; // ERROR_CODE_PROCESSING_METHOD_WAIT - wait 20 seconds default: break; } } //--- No errors - return ОК trade_obj.SetResultRetcode(0); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); return ERROR_CODE_PROCESSING_METHOD_OK; } //+------------------------------------------------------------------+
ポジションを開くためおよび指値注文を行うための保留中リクエストの作成を説明する最初の2つの記事では、取引サーバから受信したエラーのみを処理しました。最初のリクエストの後でエラーを受け取ると、保留中リクエストオブジェクトを作成し、残りの取引試行は保留中リクエストオブジェクトから行われました。取引メソッドには、サーバに取引注文を送信する前の、取引の許可とパラメータの有効性の予備チェックも含まれます。これらのチェック中に検出されたエラーは、保留中リクエストによって処理されませんでした。
本稿では、取引注文を送信する前にエラーを事前に定義した後、取引メソッドに保留中リクエストの作成を追加します。また、保留中リクエストを作成しないすべての取引メソッド(ポジションの決済/指値注文の削除、ポジションと指値注文の変更を行うメソッド)に、保留中リクエストの作成を追加します。
ポジションを開くための取引メソッドを見てみましょう。
//+------------------------------------------------------------------+ //| Open a position | //+------------------------------------------------------------------+ template<typename SL,typename TP> bool CTrading::OpenPosition(const ENUM_POSITION_TYPE type, const double volume, const string symbol, const ulong magic=ULONG_MAX, const SL sl=0, const TP tp=0, const string comment=NULL, const ulong deviation=ULONG_MAX, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE) { //--- Set the trading request result as 'true' and the error flag as "no errors" bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)type; ENUM_ACTION_TYPE action=(ENUM_ACTION_TYPE)order_type; //--- Get a symbol object by a symbol name. If failed to get CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); //--- If failed to get - write the "internal error" flag, display the message in the journal and return 'false' if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); //--- If failed to get - write the "internal error" flag, display the message in the journal and return 'false' if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Set the prices //--- If failed to set - write the "internal error" flag, set the error code in the return structure, //--- display the message in the journal and return 'false' if(!this.SetPrices(order_type,0,sl,tp,0,DFUN,symbol_obj)) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); // No quotes to process the request return false; } //--- Write the volume, deviation, comment and filling type to the request structure this.m_request.volume=volume; this.m_request.deviation=(deviation==ULONG_MAX ? trade_obj.GetDeviation() : deviation); this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment); this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : trade_obj.GetTypeFilling()); //--- Get the method of handling errors from the CheckErrors() method while checking for errors in the request parameters double pr=(type==POSITION_TYPE_BUY ? symbol_obj.AskLast() : symbol_obj.BidLast()); ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(this.m_request.volume,pr,action,order_type,symbol_obj,trade_obj,DFUN,0,this.m_request.sl,this.m_request.tp); //--- In case of trading limitations, funds insufficiency, //--- if there are limitations by StopLevel or FreezeLevel ... if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled, set the error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the trading request magic number, has no pending request ID if(this.GetPendReqID((uint)magic)==0) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the pending request object ID to the magic number and fill in the remaining unfilled fields of the trading request structure uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.type=order_type; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj.OpenPosition(type,this.m_request.volume,this.m_request.sl,this.m_request.tp,magic,comment,deviation,type_filling); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,order_type); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- Get the error handling method method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If "Wait and repeat" is received as a result of sending a request - create a pending request and end the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the trading request magic number, has no pending request ID if(this.GetPendReqID((uint)magic)==0) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the pending request object ID to the magic number and fill in the remaining unfilled fields of the trading request structure uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.type=order_type; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
メソッドのコードを見るとわかるように、取引注文のアクセス許可とエラーの事前チェックの後、また、 エラー検証メソッドから「待機と繰り返し」コードが返された後、現在、取引リクエスト構造体に存在するパラメータを持つ保留中リクエストを作成して、取引メソッドを終了します。その後、保留中リクエストオブジェクトが引き継ぎます。試行回数で設定された回数だけ、パラメータで指定された取引リクエストを再送信します。
最初のチェックに合格すると、取引注文がサーバに送信されます。次に、取引サーバの戻りコードがチェックされます。結果が「待機して繰り返す」の場合、指値注文が生成され、取引メソッドが終了されます。新たに作成された保留中リクエストオブジェクトから、さらに取引が試行されます。
保留中リクエストオブジェクトを生成する操作ロジック全体は、すべての取引メソッドで指定されます。最初のチェック後に保留中リクエストを作成するためのブロックと取引サーバーエラーを受信した後に保留中リクエストを作成するためのブロックは色で強調表示されています。自習用に次の要素が用意されています。
以下は、ポジションのストップ注文を変更するメソッドです。
//+------------------------------------------------------------------+ //| Modify a position | //+------------------------------------------------------------------+ template<typename SL,typename TP> bool CTrading::ModifyPosition(const ulong ticket,const SL sl=WRONG_VALUE,const TP tp=WRONG_VALUE) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=ACTION_TYPE_MODIFY; //--- Get an order object by ticket COrder *order=this.GetOrderObjByTicket(ticket); if(order==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return false; } ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder(); //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Set the prices //--- If failed to set - write the "internal error" flag, set the error code in the return structure, //--- display the message in the journal and return 'false' if(!this.SetPrices(order_type,0,(sl==WRONG_VALUE ? order.StopLoss() : sl),(tp==WRONG_VALUE ? order.TakeProfit() : tp),0,DFUN,symbol_obj)) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); // No quotes to process the request return false; } //--- If there are trading limitations, there are StopLevel/FreezeLevel limitations - play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,this.m_request.sl,this.m_request.tp,ticket); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true)); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true)); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the position ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true)); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write a type of a conducted operation, as well as a symbol and a ticket of a modified position to the request structure this.m_request.action=TRADE_ACTION_SLTP; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj.ModifyPosition(ticket,this.m_request.sl,this.m_request.tp); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true)); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025) trade_obj.PlaySoundError(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true)); method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request - //--- set the last error code to the return structure and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and break the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the order ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write a type of a conducted operation, as well as a symbol and a ticket of a modified position to the request structure this.m_request.action=TRADE_ACTION_SLTP; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
以下は、ポジションを決済する関数です。
//+------------------------------------------------------------------+ //| Close a position in full | //+------------------------------------------------------------------+ bool CTrading::ClosePosition(const ulong ticket,const double volume=WRONG_VALUE,const string comment=NULL,const ulong deviation=ULONG_MAX) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE; //--- Get an order object by ticket COrder *order=this.GetOrderObjByTicket(ticket); if(order==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return false; } ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder(); //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); //--- If failed to get the symbol object, display the message and return 'false' if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Update symbol quotes if(!symbol_obj.RefreshRates()) { trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); this.AddErrorCodeToList(10021); // No quotes to handle the request if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); return false; } //--- Write a deviation and a comment to the request structure this.m_request.deviation=(deviation==ULONG_MAX ? trade_obj.GetDeviation() : deviation); this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment); //--- If there are trading limitations, //--- there are limitations on FreezeLevel - play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,0,0,ticket); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the position ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the trading operation type, symbol, ticket and volume to the request structure this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.volume=volume; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=(volume==WRONG_VALUE ? trade_obj.ClosePosition(ticket,comment,deviation) : trade_obj.ClosePositionPartially(ticket,volume,comment,deviation)); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder()); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,(int)order.TypeOrder()); method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If "Wait and repeat" is received as a result of sending a request - //--- create a pending request and break the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the position ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the trading operation type, symbol, ticket and volume to the request structure this.m_request.action=TRADE_ACTION_DEAL; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.volume=volume; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
以下は、反対方向のポジションによってポジションを決済するメソッドです。
//+------------------------------------------------------------------+ //| Close a position by an opposite one | //+------------------------------------------------------------------+ bool CTrading::ClosePositionBy(const ulong ticket,const ulong ticket_by) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE_BY; //--- Get an order object by ticket COrder *order=this.GetOrderObjByTicket(ticket); if(order==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return false; } ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder(); //--- Get a symbol object by a position ticket CSymbol *symbol_obj=this.GetSymbolObjByPosition(ticket,DFUN); if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- trading object of a closed position CTradeObj *trade_obj_pos=this.GetTradeObjByPosition(ticket,DFUN); if(trade_obj_pos==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } if(!this.m_account.IsHedge()) { trade_obj_pos.SetResultRetcode(MSG_ACC_UNABLE_CLOSE_BY); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); return false; } //--- check the presence of an opposite position if(!this.CheckPositionAvailablity(ticket_by,DFUN)) { trade_obj_pos.SetResultRetcode(MSG_LIB_SYS_ERROR_POSITION_BY_ALREADY_CLOSED); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); return false; } //--- trading object of an opposite position CTradeObj *trade_obj_pos_by=this.GetTradeObjByPosition(ticket_by,DFUN); if(trade_obj_pos_by==NULL) { trade_obj_pos.SetResultRetcode(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- If a symbol of a closed position is not equal to an opposite position's one, inform of that and exit if(symbol_obj.Name()!=trade_obj_pos_by.GetSymbol()) { trade_obj_pos.SetResultRetcode(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_CLOSE_BY_SYMBOLS_UNEQUAL)); return false; } //--- Update symbol quotes if(!symbol_obj.RefreshRates()) { trade_obj_pos.SetResultRetcode(10021); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); this.AddErrorCodeToList(10021); // No quotes to handle the request if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); return false; } //--- If there are trading limitations, there are FreezeLevel limitations - play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj_pos,DFUN,0,0,0,ticket); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj_pos.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj_pos.PlaySoundError(action,order_type); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj_pos.SetResultRetcode(code); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds()) trade_obj_pos.PlaySoundError(action,order_type); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the position ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Play the error sound if(this.IsUseSounds()) trade_obj_pos.PlaySoundError(action,order_type); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj_pos.SetResultRetcode(code); trade_obj_pos.SetResultComment(CMessage::Text(trade_obj_pos.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the trading operation type, symbol and tickets of two positions to the request structure this.m_request.action=TRADE_ACTION_CLOSE_BY; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.position_by=ticket_by; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj_pos.ClosePositionBy(ticket,ticket_by); //--- If the request is successful, play the success sound set for a symbol trading object for this type of trading operation if(res || trade_obj_pos.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj_pos.PlaySoundSuccess(action,(int)order.TypeOrder()); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj_pos.GetResultRetcode())); if(this.IsUseSounds()) trade_obj_pos.PlaySoundError(action,(int)order.TypeOrder()); method=this.ResultProccessingMethod(trade_obj_pos.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj_pos.SpreadMultiplier(),symbol_obj,trade_obj_pos); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If "Wait and repeat" is received as a result of sending a request - //--- create a pending request and break the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the position ticket is not present in the list if(this.GetIndexPendingRequestByPosition(ticket)==WRONG_VALUE) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the trading operation type, symbol and tickets of two positions to the request structure this.m_request.action=TRADE_ACTION_CLOSE_BY; this.m_request.symbol=symbol_obj.Name(); this.m_request.position=ticket; this.m_request.position_by=ticket_by; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj_pos.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
以下は、指値注文を出すメソッドです。
//+------------------------------------------------------------------+ //| Place a pending order | //+------------------------------------------------------------------+ template<typename PS,typename PL,typename SL,typename TP> bool CTrading::PlaceOrder(const ENUM_ORDER_TYPE order_type, const double volume, const string symbol, const PS price_stop, const PL price_limit=0, const SL sl=0, const TP tp=0, const ulong magic=ULONG_MAX, const string comment=NULL, const datetime expiration=0, const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=(ENUM_ACTION_TYPE)order_type; //--- Get a symbol object by a symbol name CSymbol *symbol_obj=this.m_symbols.GetSymbolObjByName(symbol); if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- Get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Set the prices //--- If failed to set - write the "internal error" flag, set the error code in the return structure, //--- display the message in the journal and return 'false' if(!this.SetPrices(order_type,price_stop,sl,tp,price_limit,DFUN,symbol_obj)) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); // No quotes to process the request return false; } //--- Write the volume, comment, as well as expiration and filling types to the request structure this.m_request.volume=volume; this.m_request.comment=(comment==NULL ? trade_obj.GetComment() : comment); this.m_request.type_time=(type_time>WRONG_VALUE ? type_time : trade_obj.GetTypeExpiration()); this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : trade_obj.GetTypeFilling()); //--- In case of trading limitations, funds insufficiency, //--- there are limitations on StopLevel - play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(this.m_request.volume, this.m_request.price, action, order_type, symbol_obj, trade_obj, DFUN, this.m_request.stoplimit, this.m_request.sl, this.m_request.tp); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the trading request magic number, has no pending request ID if(this.GetPendReqID((uint)magic)==0) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the request ID to the magic number, while a symbol name is set in the request structure, //--- trading operation and order types uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.symbol=symbol_obj.Name(); this.m_request.action=TRADE_ACTION_PENDING; this.m_request.type=order_type; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj.SetOrder(order_type, this.m_request.volume, this.m_request.price, this.m_request.sl, this.m_request.tp, this.m_request.stoplimit, magic, comment, this.m_request.expiration, this.m_request.type_time, this.m_request.type_filling); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,order_type); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If "Wait and repeat" is received as a result of sending a request - create a pending request and end the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the trading request magic number, has no pending request ID if(this.GetPendReqID((uint)magic)==0) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Write the request ID to the magic number, while a symbol name is set in the request structure, //--- trading operation and order types uint mn=(magic==ULONG_MAX ? (uint)trade_obj.GetMagic() : (uint)magic); this.SetPendReqID((uchar)id,mn); this.m_request.magic=mn; this.m_request.symbol=symbol_obj.Name(); this.m_request.action=TRADE_ACTION_PENDING; this.m_request.type=order_type; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
以下は、指値注文を修正するメソッドです。
//+------------------------------------------------------------------+ //| Modify a pending order | //+------------------------------------------------------------------+ template<typename PS,typename PL,typename SL,typename TP> bool CTrading::ModifyOrder(const ulong ticket, const PS price=WRONG_VALUE, const SL sl=WRONG_VALUE, const TP tp=WRONG_VALUE, const PL limit=WRONG_VALUE, datetime expiration=WRONG_VALUE, const ENUM_ORDER_TYPE_TIME type_time=WRONG_VALUE, const ENUM_ORDER_TYPE_FILLING type_filling=WRONG_VALUE) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=ACTION_TYPE_MODIFY; //--- Get an order object by ticket COrder *order=this.GetOrderObjByTicket(ticket); if(order==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return false; } ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder(); //--- Get a symbol object by an order ticket CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN); if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Set the prices //--- If failed to set - write the "internal error" flag, set the error code in the return structure, //--- display the message in the journal and return 'false' if(!this.SetPrices(order_type, (price>0 ? price : order.PriceOpen()), (sl>0 ? sl : sl<0 ? order.StopLoss() : 0), (tp>0 ? tp : tp<0 ? order.TakeProfit() : 0), (limit>0 ? limit : order.PriceStopLimit()), DFUN,symbol_obj)) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); // No quotes to process the request return false; } //--- Write the filling type, as well as expiration date and type to the request structure this.m_request.type_filling=(type_filling>WRONG_VALUE ? type_filling : order.TypeFilling()); this.m_request.expiration=(expiration>WRONG_VALUE ? expiration : order.TimeExpiration()); this.m_request.type_time=(type_time>WRONG_VALUE ? type_time : order.TypeTime()); //--- If there are trading limitations, //--- StopLevel or FreezeLevel limitations, play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,this.m_request.price,action,order_type,symbol_obj,trade_obj,DFUN,this.m_request.stoplimit,this.m_request.sl,this.m_request.tp,ticket); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds() && trade_obj.GetResultRetcode()!=10025) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the order ticket is not present in the list if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type,(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Set the trading operation type, as well as modified order's symbol and ticket in the request structure this.m_request.action=TRADE_ACTION_MODIFY; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj.ModifyOrder(ticket,price,sl,tp,limit,expiration,type_time,type_filling); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,(int)order.TypeOrder(),(sl<0 ? false : true),(tp<0 ? false : true),(price>0 || limit>0 ? true : false)); //--- Get the error handling method method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and break the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the order ticket is not present in the list if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Set the trading operation type, as well as modified order's symbol and ticket in the request structure this.m_request.action=TRADE_ACTION_MODIFY; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
以下は、指値注文を削除するメソッドです。
//+------------------------------------------------------------------+ //| Remove a pending order | //+------------------------------------------------------------------+ bool CTrading::DeleteOrder(const ulong ticket) { bool res=true; this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_NO_ERROR; ENUM_ACTION_TYPE action=ACTION_TYPE_CLOSE; //--- Get an order object by ticket COrder *order=this.GetOrderObjByTicket(ticket); if(order==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_ORD_OBJ)); return false; } ENUM_ORDER_TYPE order_type=(ENUM_ORDER_TYPE)order.TypeOrder(); //--- Get a symbol object by an order ticket CSymbol *symbol_obj=this.GetSymbolObjByOrder(ticket,DFUN); if(symbol_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_SYM_OBJ)); return false; } //--- get a trading object from a symbol object CTradeObj *trade_obj=symbol_obj.GetTradeObj(); if(trade_obj==NULL) { this.m_error_reason_flags=TRADE_REQUEST_ERR_FLAG_INTERNAL_ERR; if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_ERROR_FAILED_GET_TRADE_OBJ)); return false; } //--- Update symbol quotes if(!symbol_obj.RefreshRates()) { trade_obj.SetResultRetcode(10021); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); this.AddErrorCodeToList(10021); // No quotes to handle the request if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(DFUN,CMessage::Text(10021)); return false; } //--- If there are trading limitations, //--- there are limitations on FreezeLevel - play the error sound and exit ENUM_ERROR_CODE_PROCESSING_METHOD method=this.CheckErrors(0,0,action,order_type,symbol_obj,trade_obj,DFUN,0,0,0,ticket); if(method!=ERROR_CODE_PROCESSING_METHOD_OK) { //--- If trading is completely disabled if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { trade_obj.SetResultRetcode(MSG_LIB_TEXT_TRADING_DISABLE); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_DISABLE)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "abort trading operation" - set the last error code to the return structure, //--- display a journal message, play the error sound and exit if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRADING_OPERATION_ABORTED)); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); return false; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and return 'false' if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the order ticket is not present in the list if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Play the error sound if(this.IsUseSounds()) trade_obj.PlaySoundError(action,order_type); //--- set the last error code to the return structure int code=this.m_list_errors.At(this.m_list_errors.Total()-1); if(code!=NULL) { if(code==MSG_LIB_TEXT_TERMINAL_NOT_TRADE_ENABLED || code==MSG_LIB_TEXT_EA_NOT_TRADE_ENABLED) code=10027; trade_obj.SetResultRetcode(code); trade_obj.SetResultComment(CMessage::Text(trade_obj.GetResultRetcode())); } //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Set the trading operation type, as well as deleted order's symbol and ticket in the request structure this.m_request.action=TRADE_ACTION_REMOVE; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; //--- Set the number of trading attempts and create a pending request uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); } return false; } } //--- In the loop by the number of attempts for(int i=0;i<this.m_total_try;i++) { //--- Send the request res=trade_obj.DeleteOrder(ticket); //--- If the request is executed successfully or the asynchronous order sending mode is set, play the success sound //--- set for a symbol trading object for this type of trading operation and return 'true' if(res || trade_obj.IsAsyncMode()) { if(this.IsUseSounds()) trade_obj.PlaySoundSuccess(action,(int)order.TypeOrder()); return true; } //--- If the request is not successful, play the error sound set for a symbol trading object for this type of trading operation else { if(this.m_log_level>LOG_LEVEL_NO_MSG) ::Print(CMessage::Text(MSG_LIB_TEXT_TRY_N),string(i+1),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(trade_obj.GetResultRetcode())); if(this.IsUseSounds()) trade_obj.PlaySoundError(action,(int)order.TypeOrder()); //--- Get the error handling method method=this.ResultProccessingMethod(trade_obj.GetResultRetcode()); //--- If "Disable trading for the EA" is received as a result of sending a request, enable the disabling flag and end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_DISABLE) { this.SetTradingDisableFlag(true); break; } //--- If "Exit the trading method" is received as a result of sending a request, end the attempt loop if(method==ERROR_CODE_PROCESSING_METHOD_EXIT) { break; } //--- If "Correct the parameters and repeat" is received as a result of sending a request - //--- correct the parameters and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_CORRECT) { this.RequestErrorsCorrecting(this.m_request,order_type,trade_obj.SpreadMultiplier(),symbol_obj,trade_obj); continue; } //--- If "Update data and repeat" is received as a result of sending a request - //--- update data and start the next iteration if(method==ERROR_CODE_PROCESSING_METHOD_REFRESH) { symbol_obj.Refresh(); continue; } //--- If the check result is "waiting" - set the last error code to the return structure and display the message in the journal, //--- create a pending request and break the loop if(method>ERROR_CODE_PROCESSING_METHOD_REFRESH) { //--- If the pending request object with the order ticket is not present in the list if(this.GetIndexPendingRequestByOrder(ticket)==WRONG_VALUE) { //--- Waiting time in milliseconds: //--- for the "Wait and repeat" handling method, the waiting value corresponds to the 'method' value, //--- for the "Create a pending request" handling method - till there is a zero waiting time ulong wait=method; //--- Look for the least of the possible IDs. If failed to find //--- or in case of an error while updating the current symbol data, return 'false' int id=this.GetFreeID(); if(id<1 || !symbol_obj.RefreshRates()) return false; //--- Set the trading operation type, as well as deleted order's symbol and ticket in the request structure this.m_request.action=TRADE_ACTION_REMOVE; this.m_request.symbol=symbol_obj.Name(); this.m_request.order=ticket; //--- Set the number of trading attempts, create a pending request and break the loop uchar attempts=(this.m_total_try < 1 ? 1 : this.m_total_try); this.CreatePendingRequest((uchar)id,attempts,wait,this.m_request,trade_obj.GetResultRetcode(),symbol_obj); break; } } } } //--- Return the result of sending a trading request in a symbol trading object return res; } //+------------------------------------------------------------------+
メソッドのリストからわかるように、保留中リクエストを作成するほとんどすべてのブロックは類似しており、取引リクエスト構造体の入力、取引試行回数の設定、保留中リクエストの作成、取引メソッドの終了を伴います。上記で考慮されたクラスタイマーからの保留中リクエストオブジェクトは、その後に引き継ぎます。
これは、保留中リクエストを使用して作業を実装するために必要な取引クラスのすべての変更です。
OnInit()メソッドが取引クラスの追加パラメータ(取引イベントコレクションクラスオブジェクトへのポインタ)を受け入れるようになったため、そのパラメータをそこで渡す必要があります。
これはCEngineライブラリ基本オブジェクトクラスで行われます。
Engine.mqhファイルを開き、TradingOnInit()メソッドを変更します。
//--- Pass the pointers to all the necessary collections to the trading class void TradingOnInit(void) { this.m_trading.OnInit(this.GetAccountCurrent(),m_symbols.GetObject(),m_market.GetObject(),m_history.GetObject(),m_events.GetObject()); }
ここで、CTrading取引クラスのOnInit()メソッドを呼び出します。ここで、口座取引イベントコレクションクラスへのポインタは、最後のパラメータとして取引クラスに渡されます。
テスト
保留中リクエストオブジェクトをテストするには、前の記事のEAをそのまま使用します。
ただし、\MQL5\Experts\TestDoEasy\Part28\でTestDoEasyPart28.mq5として保存します。
保留中リクエストを確認するために行うことは次のとおりです。
端末で自動取引ボタンを無効にしてテストEAの取引パネルでポジションを開くボタンをクリックします。保留中リクエストの作成に関するものを含む、取引リクエストの送信のと操作ログエントリの適切さに関するエラーを取得します。
自動取引ボタンを再度有効にして繰り返し取引が試行されるまで待機します(端末によって取引が無効になっている場合、20秒の時間が設定されています)。次の試行の時間になると、ポジションが開かれれ、保留中リクエストが処理を完了して削除されたことを通知する適切な操作ログエントリが表示されます。
2019.12.12 15:36:17.878 automated trading is disabled 2019.12.12 15:36:23.206 CTrading::OpenPosition<uint,uint>: Invalid request: 2019.12.12 15:36:23.206 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.12 15:36:23.206 Correction of trade request parameters ... 2019.12.12 15:36:23.207 Pending request created #1: 2019.12.12 15:36:23.207 ================== Pending trade request's parameters ================== 2019.12.12 15:36:23.207 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 15:36:23.207 - Trade request ID: #1 2019.12.12 15:36:23.207 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 15:36:23.207 - Request creation time: 2019.12.12 10:36:23.006 2019.12.12 15:36:23.207 - Price at time of request create: : 1.11353 2019.12.12 15:36:23.207 - Request activation time: 2019.12.12 10:36:43.006 2019.12.12 15:36:23.207 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 15:36:23.207 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 15:36:23.207 - Total trade attempts: 5 2019.12.12 15:36:23.207 ================== Trade request's parameters ================== 2019.12.12 15:36:23.207 - Trade operation type: Place market order 2019.12.12 15:36:23.207 - Trade symbol: EURUSD 2019.12.12 15:36:23.207 - Requested volume for a deal in lots: 0.10 2019.12.12 15:36:23.207 - Price: 1.11356 2019.12.12 15:36:23.207 - Stop Loss level of the order: 1.11206 2019.12.12 15:36:23.207 - Take Profit level of the order: 1.11506 2019.12.12 15:36:23.207 - Maximal deviation from the price: 5 2019.12.12 15:36:23.207 - Order type: Market-order Buy 2019.12.12 15:36:23.207 - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK) 2019.12.12 15:36:23.207 - Magic number: 25821307 2019.12.12 15:36:23.207 - Order comment: "TestDoEasyPart28 by DoEasy" 2019.12.12 15:36:23.207 ================== 2019.12.12 15:36:23.207 2019.12.12 15:36:26.845 automated trading is enabled 2019.12.12 15:36:43.536 Retry trading attempt #1 2019.12.12 15:36:43.883 - Position is open: 2019.12.12 10:36:43.797 - 2019.12.12 15:36:43.883 EURUSD Opened 0.10 Buy #494348590 [0.10 Market-order Buy #494348590] at price 1.11354, sl 1.11206, tp 1.11506, Magic number 25821307 (123), G1: 10, G2: 8, ID: 1 2019.12.12 15:36:43.883 OnDoEasyEvent: Position is open 2019.12.12 15:36:44.101 Trade request ID: #1: Pending request deleted due to execution
ポジションが開かれたら、端末の自動取引ボタンを再度無効にし、テストEA取引パネルのポジション決済ボタンをクリックします。エラーと、保留中のリクエストの作成に関するものを含む適切な操作ログエントリを取得します。P
自動取引ボタンを再度有効にして繰り返し取引が試行されるまで待機します。次の試行の時間になると、ポジションが開かれれ、保留中リクエストが処理を完了して削除されたことを通知する適切な操作ログエントリが表示されます。
2019.12.12 15:37:02.347 automated trading is disabled 2019.12.12 15:37:06.566 CTrading::ClosePosition: Invalid request: 2019.12.12 15:37:06.566 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.12 15:37:06.566 Correction of trade request parameters ... 2019.12.12 15:37:06.566 Pending request created #1: 2019.12.12 15:37:06.566 ================== Pending trade request's parameters ================== 2019.12.12 15:37:06.566 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 15:37:06.566 - Trade request ID: #1 2019.12.12 15:37:06.566 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 15:37:06.566 - Request creation time: 2019.12.12 10:37:03.586 2019.12.12 15:37:06.566 - Price at time of request create: : 1.11351 2019.12.12 15:37:06.566 - Request activation time: 2019.12.12 10:37:23.586 2019.12.12 15:37:06.566 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 15:37:06.566 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 15:37:06.566 - Total trade attempts: 5 2019.12.12 15:37:06.566 ================== Trade request's parameters ================== 2019.12.12 15:37:06.566 - Trade operation type: Place market order 2019.12.12 15:37:06.566 - Trade symbol: EURUSD 2019.12.12 15:37:06.566 - Requested volume for a deal in lots: Value not set 2019.12.12 15:37:06.566 - Price: 1.11354 2019.12.12 15:37:06.566 - Stop Loss level of the order: 1.11206 2019.12.12 15:37:06.566 - Take Profit level of the order: 1.11506 2019.12.12 15:37:06.566 - Maximal deviation from the price: 5 2019.12.12 15:37:06.566 - Order type: Market-order Buy 2019.12.12 15:37:06.566 - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK) 2019.12.12 15:37:06.566 - Magic number: 0 2019.12.12 15:37:06.566 - Order comment: "TestDoEasyPart28 by DoEasy" 2019.12.12 15:37:06.566 ================== 2019.12.12 15:37:06.566 2019.12.12 15:37:11.611 automated trading is enabled 2019.12.12 15:37:25.196 Retry trading attempt #1 2019.12.12 15:37:25.679 - Position closed: 2019.12.12 10:36:43.797 - 2019.12.12 15:37:25.679 EURUSD Closed Buy #494348590 [0.10 Market-order Sell #494348941] at price 1.11349, sl 1.11206, tp 1.11506, Magic number 25821307 (123), G1: 10, G2: 8, ID: 1, Profit -0.50 USD 2019.12.12 15:37:25.679 OnDoEasyEvent: Position closed 2019.12.12 15:37:25.838 Trade request ID: #1: Pending request deleted due to execution
では、複数の取引注文の作業を一度に確認しましょう。
自動取引を無効にして、指値注文を1つずつ行うためのボタンをクリックします。注文を試行するたびに、エラーメッセージ、保留中リクエスト作成エントリおよびそのパラメータを取得します。
次に、端末で自動取引を有効にします。保留中の各取引リクエストの次の試行の時間が来るとすぐに、各リクエストの試行番号に関するメッセージが、各注文の成功した配置に関するメッセージとともに表示されます。
次に、保留中の各取引リクエストが削除され、適切なメッセージが操作ログに表示されます。
2019.12.12 17:47:16.774 automated trading is disabled 2019.12.12 17:47:20.297 CTrading::PlaceOrder<uint,int,uint,uint>: Invalid request: 2019.12.12 17:47:20.297 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.12 17:47:20.298 Correction of trade request parameters ... 2019.12.12 17:47:20.298 Pending request created #1: 2019.12.12 17:47:20.298 ================== Pending trade request's parameters ================== 2019.12.12 17:47:20.298 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 17:47:20.298 - Trade request ID: #1 2019.12.12 17:47:20.298 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 17:47:20.298 - Request creation time: 2019.12.12 12:47:18.719 2019.12.12 17:47:20.298 - Price at time of request create: : 1.11293 2019.12.12 17:47:20.298 - Request activation time: 2019.12.12 12:47:38.719 2019.12.12 17:47:20.298 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 17:47:20.298 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 17:47:20.298 - Total trade attempts: 5 2019.12.12 17:47:20.298 ================== Trade request's parameters ================== 2019.12.12 17:47:20.298 - Trade operation type: Place pending order 2019.12.12 17:47:20.298 - Trade symbol: EURUSD 2019.12.12 17:47:20.298 - Requested volume for a deal in lots: 0.10 2019.12.12 17:47:20.298 - Price: 1.11343 2019.12.12 17:47:20.298 - StopLimit level of the order: Value not set 2019.12.12 17:47:20.298 - Stop Loss level of the order: 1.11493 2019.12.12 17:47:20.298 - Take Profit level of the order: 1.11193 2019.12.12 17:47:20.298 - Order type: Pending order Sell Limit 2019.12.12 17:47:20.298 - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK) 2019.12.12 17:47:20.298 - Order expiration type: Good till cancel order 2019.12.12 17:47:20.298 - Order expiration time: Value not set 2019.12.12 17:47:20.298 - Magic number: 27525243 2019.12.12 17:47:20.298 - Order comment: "Pending order SellLimit" 2019.12.12 17:47:20.298 ================== 2019.12.12 17:47:20.298 2019.12.12 17:47:24.514 Pending request created #2: 2019.12.12 17:47:24.514 ================== Pending trade request's parameters ================== 2019.12.12 17:47:24.514 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 17:47:24.514 - Trade request ID: #2 2019.12.12 17:47:24.514 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 17:47:24.514 - Request creation time: 2019.12.12 12:47:23.638 2019.12.12 17:47:24.514 - Price at time of request create: : 1.11296 2019.12.12 17:47:24.514 - Request activation time: 2019.12.12 12:47:43.638 2019.12.12 17:47:24.514 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 17:47:24.514 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 17:47:24.514 - Total trade attempts: 5 2019.12.12 17:47:24.514 ================== Trade request's parameters ================== 2019.12.12 17:47:24.514 - Trade operation type: Place pending order 2019.12.12 17:47:24.514 - Trade symbol: EURUSD 2019.12.12 17:47:24.514 - Requested volume for a deal in lots: 0.10 2019.12.12 17:47:24.514 - Price: 1.11251 2019.12.12 17:47:24.514 - StopLimit level of the order: Value not set 2019.12.12 17:47:24.514 - Stop Loss level of the order: 1.11101 2019.12.12 17:47:24.514 - Take Profit level of the order: 1.11401 2019.12.12 17:47:24.514 - Order type: Pending order Buy Limit 2019.12.12 17:47:24.514 - Order execution type: The order is executed exclusively in the specified volume, otherwise it is canceled (FOK) 2019.12.12 17:47:24.514 - Order expiration type: Good till cancel order 2019.12.12 17:47:24.514 - Order expiration time: Value not set 2019.12.12 17:47:24.514 - Magic number: 39387259 2019.12.12 17:47:24.514 - Order comment: "Pending order BuyLimit" 2019.12.12 17:47:24.514 ================== 2019.12.12 17:47:24.514 2019.12.12 17:47:29.167 automated trading is enabled 2019.12.12 17:47:45.796 Retry trading attempt #1 2019.12.12 17:47:46.045 Retry trading attempt #1 2019.12.12 17:47:46.256 - Pending order placed: 2019.12.12 12:47:46.319 - 2019.12.12 17:47:46.256 EURUSD Placed 0.10 Pending order Sell Limit #494419747 at price 1.11343, sl 1.11493, tp 1.11193, Magic number 27525243 (123), G1: 4, G2: 10, ID: 1 2019.12.12 17:47:46.256 - Pending order placed: 2019.12.12 12:47:46.162 - 2019.12.12 17:47:46.256 EURUSD Placed 0.10 Pending order Buy Limit #494419742 at price 1.11251, sl 1.11101, tp 1.11401, Magic number 39387259 (123), G1: 9, G2: 5, ID: 2 2019.12.12 17:47:46.256 OnDoEasyEvent: Pending order placed 2019.12.12 17:47:46.256 OnDoEasyEvent: Pending order placed 2019.12.12 17:47:46.505 Trade request ID: #2: Pending request deleted due to execution 2019.12.12 17:47:46.505 Trade request ID: #1: Pending request deleted due to execution
次に、両方の指値注文を一度に削除してみましょう。
端末で自動取引ボタンを無効にしてテストEA取引パネルですべての未決注文を削除するボタンをクリックします(未決を削除)エラーメッセージと、保留中リクエストの作成に関するエントリ、および削除された各注文のパラメータを取得します。
次に、端末で自動取引を有効にします。保留中の各取引リクエストの次の試行の時間が来るとすぐに、各リクエストの試行番号に関するメッセージが、各注文の成功した削除に関するメッセージとともに表示されます。
次に、保留中の各取引リクエストが削除され、適切なメッセージが操作ログに表示されます。
2019.12.12 17:47:57.310 automated trading is disabled 2019.12.12 17:48:03.105 CTrading::DeleteOrder: Invalid request: 2019.12.12 17:48:03.105 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.12 17:48:03.105 Correction of trade request parameters ... 2019.12.12 17:48:03.105 Pending request created #1: 2019.12.12 17:48:03.106 ================== Pending trade request's parameters ================== 2019.12.12 17:48:03.106 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 17:48:03.106 - Trade request ID: #1 2019.12.12 17:48:03.106 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 17:48:03.106 - Request creation time: 2019.12.12 12:48:00.305 2019.12.12 17:48:03.106 - Price at time of request create: : 1.11300 2019.12.12 17:48:03.106 - Request activation time: 2019.12.12 12:48:20.305 2019.12.12 17:48:03.106 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 17:48:03.106 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 17:48:03.106 - Total trade attempts: 5 2019.12.12 17:48:03.106 ================== Trade request's parameters ================== 2019.12.12 17:48:03.106 - Trade operation type: Delete the pending order placed previously 2019.12.12 17:48:03.106 - Order ticket: 494419747 2019.12.12 17:48:03.106 ================== 2019.12.12 17:48:03.106 2019.12.12 17:48:03.106 CTrading::DeleteOrder: Invalid request: 2019.12.12 17:48:03.106 There is no permission to conduct trading operations in the terminal (the "AutoTrading" button is disabled) 2019.12.12 17:48:03.106 Correction of trade request parameters ... 2019.12.12 17:48:03.106 Pending request created #2: 2019.12.12 17:48:03.106 ================== Pending trade request's parameters ================== 2019.12.12 17:48:03.106 - Pending request type: Pending request that was created as a result of the server code 2019.12.12 17:48:03.106 - Trade request ID: #2 2019.12.12 17:48:03.106 - Return code based on which the request was created: 10027 "Autotrading disabled by client terminal" 2019.12.12 17:48:03.106 - Request creation time: 2019.12.12 12:48:00.305 2019.12.12 17:48:03.106 - Price at time of request create: : 1.11300 2019.12.12 17:48:03.106 - Request activation time: 2019.12.12 12:48:20.305 2019.12.12 17:48:03.106 - Waiting time between trading attempts: 20000 (00:00:20) 2019.12.12 17:48:03.106 - Current trading attempt: Waiting for the onset time of the first trading attempt 2019.12.12 17:48:03.106 - Total trade attempts: 5 2019.12.12 17:48:03.106 ================== Trade request's parameters ================== 2019.12.12 17:48:03.106 - Trade operation type: Delete the pending order placed previously 2019.12.12 17:48:03.106 - Order ticket: 494419742 2019.12.12 17:48:03.106 ================== 2019.12.12 17:48:03.106 2019.12.12 17:48:09.073 automated trading is enabled 2019.12.12 17:48:24.428 Retry trading attempt #1 2019.12.12 17:48:24.428 CTrading::OnTimer: Trade operation type: Delete the pending order placed previously 2019.12.12 17:48:24.593 Retry trading attempt #1 2019.12.12 17:48:24.593 CTrading::OnTimer: Trade operation type: Delete the pending order placed previously 2019.12.12 17:48:24.771 - Pending order removed: 2019.12.12 12:47:46.319 - 2019.12.12 17:48:24.771 EURUSD Deleted 0.10 Pending order Sell Limit #494419747 at price 1.11343, sl 1.11493, tp 1.11193, Magic number 27525243 (123), G1: 4, G2: 10, ID: 1 2019.12.12 17:48:24.771 - Pending order removed: 2019.12.12 12:47:46.162 - 2019.12.12 17:48:24.771 EURUSD Deleted 0.10 Pending order Buy Limit #494419742 at price 1.11251, sl 1.11101, tp 1.11401, Magic number 39387259 (123), G1: 9, G2: 5, ID: 2 2019.12.12 17:48:24.771 OnDoEasyEvent: Pending order removed 2019.12.12 17:48:24.771 OnDoEasyEvent: Pending order removed 2019.12.12 17:48:25.024 Trade request ID: #2: Pending request deleted due to execution 2019.12.12 17:48:25.024 Trade request ID: #1: Pending request deleted due to execution
操作ログのデバッグメッセージによると、保留中の取引リクエストは計画どおりにアクティブ化され、作業が完了した後に削除されます。
これは、保留中リクエストオブジェクトの最終バージョンではありません。
代わりに、これはMQL5ヘッジ勘定での概念の確認にすぎません。
注意事項
記事で説明されている保留中リクエスト、および実際の取引で添付されているテスト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部:プログラムリソースの作成と格納
第21部:取引クラス
- 基本クロスプラットフォーム取引オブジェクト
第22部:取引クラス - 基本取引クラス、制限の検証
第23部:取引クラス
- 基本取引クラス、パラメータ有効性の検証
第24部:取引クラス - 基本取引クラス、無効なパラメータの自動修正
第25部:取引クラス
- 取引サーバによって返されたエラーを処理する基本取引クラス
第26部:指値取引リクエストの使用 - 初期実装(ポジションを開く)第27部:指値取引リクエストの使用
- 指数注文