
クイック手動取引ツールキット: ポジションと指値注文の使用
内容
はじめに
手動取引を好むトレーダーを支援するための基本的な機能は以前に作成しました。主に注文を便利に出すことに焦点を当てたので、ほとんどの関数は注文を出すことに関連していました。ただし、手動自動にかかわらず、取引戦略すべてには、市場で作業するにあたって3つの段階があります。これらには注文を出すルール、ポジション管理、決済条件が含まれます。今のところ、ツールキットには1番目の段階のみが含まれますため、さらなる開発として、ポジションまたは指値注文を処理する機会を追加し、取引を成立させるための条件を拡大します。すべての計算はツールキットで実行し、決定はトレーダーがおこなう必要があります。
問題の定式化
まず、新しい機能を実装するために必要なタスクの範囲を決定します。現在のアプリケーションの開発を継続する主な段階を決定しましょう。
- アプリケーション構造の改訂: アプリケーションは元々、一連のタスクボタンを備えたメインウィンドウとして作成されました。そのうちの2つは、市場でのポジションと指値注文を設定するためのツールを備えたモーダルウィンドウを開きました。他の3つのボタンは、成行ポジションを決済し、すべての指値注文を削除するためのシンプルな機能を提供します。次に、現在のポジションを管理し、指値注文を編集するためのインターフェイスを追加する必要があります。
- 注文操作モードの拡張: 以前は、すべての収益/損失を伴う注文を決済することができました。ここでは、ポジションタイプごとに分割され、すべての注文または選択された注文を決済するためのさまざまな条件を設定する、より柔軟な機能が必要です。指値注文については、ツールキットによって以前に作成された注文のみを一括決済することができましたが、これは十分ではありません。別の指値注文を削除したり、変更したりできるべきです。また、成行注文と指値注文の別々のリストがあると便利です。
それぞれの段階を個別に詳しく見ていきましょう。
アプリケーション構造の再訪問
最初に、すでに実装されているものを見てみましょう。以下の図1は、開始/作成と終了/削除の2つのカテゴリでタスクを実行するメインブロックを示しています。3番目のカテゴリは、手動による管理と変更です。
図1 ツールキットのメインブロック
3つのタブを作成します。最初のものは、図1に示す関数に使用されます。他の2つのタブでは、ポジションと未決注文を処理するための機能を実装します。
図2 新しいアプリケーション構造
以前はメインウィンドウにあったすべての機能は、[Trading](取引)タブに実装されます。ポジションコントロールは、このツールを介して開かれた既存ポジションの表を備えています。これらのポジションを操作するためのコマンドもそこで実装されます。指値注文管理では、ツールキットを介して作成された注文と、指値注文を決済して変更するための管理が行われます。タブについて詳しく見ていきましょう。
図3 成行ポジションコントロールタブ
図3は、[Market PositionsControl](成行ポジションコントロール)タブを示しています。タブには次の要素が含まれています。
- [Market Orders](成行注文)タブ: アプリケーションによって開かれた現在のすべてのポジションに関する情報を表示します。これは、MetaTrader5の[トレード]タブの表に似ています。
- 3つの入力フィールド: これらは表の列(ボリューム、ストップロス、テイクプロフィット)に対応し、リンクされています。
- 2つのボタン: 表の行をクリックすると、編集可能なポジションパラメータが入力フィールドに表示されます。[Edit](編集)をクリックすると、リストで選択したポジションのストップロスとテイクプロフィットを変更したり、削除したりすることができます。[Close](決済)ボタンは、現在の価格でポジションを決済します。さらに、ポジションを決済するとボリューム入力フィールドが確認されます。これは、現在のポジションのロットよりも小さいロット値を選択して、ポジションを部分的に決済ことができることを意味します。
次に、図4の[Pending Order Control](指値注文コントロール)タブを見てください。
図4 指値注文コントロール
これは前のものと非常によく似ています。
- 指値注文の表このツールキットを介して行われた指値注文のリストが含まれています。
- 3つの入力フィールド:表で指値注文が選択されている場合、現在の執行価格を変更したり、ストップロスとテイクプロフィットを編集または削除したりできます。
- 2つのボタン:成行ポジションの表とは対照的に、[Edit](編集)ボタンは、選択した指値注文を編集するために3つの入力フィールドすべてにアクセスします。[Close](決済)ボタンは、注文を決済します。
[Trading](取引)タブに戻り、新しい機能のために変更してみましょう。まず、利益を上げたポジションや損失を被ったポジションを決済するための既存のツールを修正しましょう。ロングポジションに加えてショートポジションを決済することが可能になります。これは、決済モード切替ボタンを介して行われます。
図5 成行ポジション決済機能の拡張
図5に示すように、[Close BUY profit](利益のある買いポジションを決済)、[Close SELL profit](利益のある売りポジションを決済)、[Close BUY loss](損失のある買いポジションを決済)、[Close SELL loss](損失のある売りポジションを決済)の4つの新しいボタンがあります。ボタンの右側に追加の切替ボタンがあります。 それらをより詳細に検討しましょう。切替ボタンは類似しているため、以下の説明がすべてに適用されます。
- All(すべて)(デフォルト値):ボタンに制限を設定せず、選択したすべての項目を決済します。
- >Point(ポイント):利益/損失が指定された値(ポイント単位)よりも大きい、選択されたタイプのすべてのポジションを決済します。
- Currency(通貨): 利益/損失が指定された値(預金通貨単位)よりも大きい、選択されたタイプのすべてのポジションを決済します。
- Sum>Points(合計>ポイント):合計利益/損失が指定された値(ポイント単位)よりも大きい、選択されたタイプのすべてのポジションを決済します。<分
- Sum>Currency(合計>通貨):合計利益/損失が指定された値(預金通貨単位)よりも大きい、選択されたタイプのすべてのポジションを決済します。
図5に示す設定の例(sum>currencyオプションですべての損失ポジションを決済)を考えてみましょう。この場合、ツールキットは以前に開いたすべてのポジションを見つけて利益を要約し、損失が預金通貨で10ユニットを超える場合は、すべてのポジションを決済します。
ツールキット追加の実装
基礎として、「クイック手動取引ツールキット: 基本機能」稿で以前に作成したプロジェクトを使用します。まず、図2に示すように、メインウィンドウを再構築する必要があります。これをおこなうには、CProgram基本クラスにCreateTabs()メソッドを作成してTabインターフェイス要素を追加し、それをMainWindow.mqhに実装します。
//+------------------------------------------------------------------+ //| Create a group with tabs | //+------------------------------------------------------------------+ bool CFastTrading::CreateTabs(const int x_gap,const int y_gap) { //--- Store the pointer to the main control m_tab.MainPointer(m_main_window); //--- Properties m_tab.Font(m_base_font); m_tab.FontSize(m_base_font_size); m_tab.LabelColor(clrWhite); m_tab.LabelColorHover(clrWhite); m_tab.IsCenterText(true); m_tab.AutoXResizeMode(true); m_tab.AutoYResizeMode(true); m_tab.AutoXResizeRightOffset(5); m_tab.AutoYResizeBottomOffset(5); m_tab.TabsYSize(27); m_tab.GetButtonsGroupPointer().Font(m_base_font); m_tab.GetButtonsGroupPointer().FontSize(m_base_font_size); //--- Add tabs with the specified properties string tabs_names[3]; tabs_names[0]=TRADING; tabs_names[1]=CAPTION_M_CONTROL_NAME; tabs_names[2]=CAPTION_P_CONTROL_NAME; for(int i=0; i<3; i++) m_tab.AddTab(tabs_names[i],180); //--- Create a control element if(!m_tab.CreateTabs(x_gap,y_gap)) return(false); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,m_tab); return(true); }
作成されたメソッド本体には、タブヘッダーとして機能する3つの新しいマクロ置換があります。これらは2つの言語でDefines.mqhファイルに追加する必要があります。
#define TRADING (m_language==RUSSIAN ? "Трейдинг" : "Trading") #define CAPTION_M_CONTROL_NAME (m_language==RUSSIAN ? "Контроль рыночных позиций" : "Market Control") #define CAPTION_P_CONTROL_NAME (m_language==RUSSIAN ? "Контроль отложенных ордеров" : "Pending Control")
新しく作成したメソッドを適用する前に、ボタンを作成するメソッドを再構築し、これらのメソッドを最初のタブにリンクする必要があります。一般的なメソッドCreateButton()を見つけて、次のように編集しましょう。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateButton(CButton &button,string text,color baseclr,int x_gap,int y_gap) { //--- Store the window pointer button.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(0,button); //--- Set properties before creation button.XSize(180); button.YSize(40); button.Font(m_base_font); button.FontSize(m_base_font_size); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(baseclr); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(baseclr); button.LabelColor(clrWhite); button.LabelColorPressed(clrWhite); button.LabelColorHover(clrWhite); button.IsCenterText(true); //--- Create a control element if(!button.CreateButton(text,x_gap,y_gap)) return(false); //--- Add a pointer to the element to the database CWndContainer::AddToElementsArray(0,button); return(true); }
次に、メインウィンドウの作成メソッドに変更を適用します。
//+------------------------------------------------------------------+ //| Creates a form for orders | //+------------------------------------------------------------------+ bool CFastTrading::CreateMainWindow(void) { //--- Add a window pointer to the window array CWndContainer::AddWindow(m_main_window); //--- Properties m_main_window.XSize(600); m_main_window.YSize(375); //--- Coordinates int x=5; int y=20; m_main_window.CaptionHeight(22); m_main_window.IsMovable(true); m_main_window.CaptionColor(m_caption_color); m_main_window.CaptionColorLocked(m_caption_color); m_main_window.CaptionColorHover(m_caption_color); m_main_window.BackColor(m_background_color); m_main_window.FontSize(m_base_font_size); m_main_window.Font(m_base_font); //--- Create the form if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y)) return(false); //--- Tabs if(!CreateTabs(5,22+27)) return(false); //--- if(!CreateButton(m_order_button[0],MARKET_ORDER_NAME+"(M)",C'87,128,255',20,10)) return(false); if(!CreateButton(m_order_button[1],PENDING_ORDER_NAME+"(P)",C'31,209,111',210,10)) return(false); if(!CreateButton(m_order_button[2],MARKET_ORDERS_PROFIT_CLOSE+"(C)",C'87,128,255',20,60)) return(false); if(!CreateButton(m_order_button[3],MARKET_ORDERS_LOSS_CLOSE+"(D)",C'87,128,255',20,110)) return(false); if(!CreateButton(m_order_button[4],PEND_ORDERS_ALL_CLOSE+"(R)",C'31,209,111',210,60)) return(false); //--- return(true); }
ここに示されているように、最初にタブを追加し、次にボタンを作成するメソッドの呼び出しを更新し、メインウィンドウのサイズを変更しました。プロジェクトのコンパイル後、すべてのボタンが最初のタブに移動します。
図6 タブの作成とボタンの最初のタブへの移動
図5に従って、必要な機能を実装するために追加のボタンと入力フィールドを作成しましょう。大きなボタンには、更新された CreateButton()メソッドを使用します。ただし、入力フィールドと切り替えボタンを作成するには、追加のメソッドを導入する必要があります。これらは、CreateModeButton()(モード切り替えボタン)とCreateModeEdit()(入力フィールド)です。それらの完全な実装は次のとおりです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateModeButton(CButton &button,string text,int x_gap,int y_gap) { //--- Store the window pointer button.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(0,button); color baseclr=clrDarkViolet; //--- Set properties before creation button.XSize(80); button.YSize(20); button.Font(m_base_font); button.FontSize(9); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(baseclr); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(baseclr); button.LabelColor(clrWhite); button.LabelColorPressed(clrWhite); button.LabelColorHover(clrWhite); button.IsCenterText(true); //--- Create a control element if(!button.CreateButton(text,x_gap,y_gap)) return(false); //--- Add a pointer to the element to the database CWndContainer::AddToElementsArray(0,button); return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateModeEdit(CTextEdit &text_edit,int x_gap,int y_gap) { //--- Store the window pointer text_edit.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(0,text_edit); //--- Properties text_edit.XSize(80); text_edit.YSize(20); text_edit.Font(m_base_font); text_edit.FontSize(m_base_font_size); text_edit.SetDigits(2); text_edit.MaxValue(99999); text_edit.StepValue(0.01); text_edit.MinValue(0.01); text_edit.SpinEditMode(true); text_edit.GetTextBoxPointer().XGap(1); text_edit.GetTextBoxPointer().XSize(80); //--- Create a control element if(!text_edit.CreateTextEdit("",x_gap,y_gap)) return(false); text_edit.SetValue(string(0.01)); text_edit.IsLocked(true); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,text_edit); return(true); }
以下は、上記のメソッドを使用してメインウィンドウを作成し、図5のボタンを追加する更新されたメソッドです。
//+------------------------------------------------------------------+ //| Creates a form for orders | //+------------------------------------------------------------------+ bool CFastTrading::CreateMainWindow(void) { //--- Add a window pointer to the window array CWndContainer::AddWindow(m_main_window); //--- Properties m_main_window.XSize(600); m_main_window.YSize(375); //--- Coordinates int x=5; int y=20; m_main_window.CaptionHeight(22); m_main_window.IsMovable(true); m_main_window.CaptionColor(m_caption_color); m_main_window.CaptionColorLocked(m_caption_color); m_main_window.CaptionColorHover(m_caption_color); m_main_window.BackColor(m_background_color); m_main_window.FontSize(m_base_font_size); m_main_window.Font(m_base_font); //--- Create the form if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y)) return(false); //--- Tabs if(!CreateTabs(5,22+27)) return(false); //--- if(!CreateButton(m_order_button[0],MARKET_ORDER_NAME+"(M)",C'87,128,255',10,10)) return(false); if(!CreateButton(m_order_button[1],PENDING_ORDER_NAME+"(P)",C'31,209,111',300,10)) return(false); if(!CreateButton(m_order_button[2],CLOSE_ALL_PROFIT+"(C)",C'87,128,255',10,10+45*1)) return(false); if(!CreateButton(m_order_button[3],PEND_ORDERS_ALL_CLOSE+"(R)",C'31,209,111',300,10+45*1)) return(false); if(!CreateButton(m_order_button[4],CLOSE_BUY_PROFIT,C'87,128,255',10,10+45*2)) return(false); if(!CreateButton(m_order_button[5],CLOSE_SELL_PROFIT,C'87,128,255',10,10+45*3)) return(false); if(!CreateButton(m_order_button[6],CLOSE_ALL_LOSS+"(D)",C'87,128,255',10,10+45*4)) return(false); if(!CreateButton(m_order_button[7],CLOSE_BUY_LOSS,C'87,128,255',10,10+45*5)) return(false); if(!CreateButton(m_order_button[8],CLOSE_SELL_LOSS,C'87,128,255',10,10+45*6)) return(false); //--- for(int i=0; i<6; i++) { if(!CreateModeButton(m_mode_button[i],"all",205-10,10+45*(i+1))) return(false); if(!CreateModeEdit(m_mode_edit[i],204-10,30+45*(i+1))) return(false); } //--- return(true); }
ここでは新しいマイクロ置換が使用されるので、適切な値をDefines.mqhに追加する必要があります。
#define CLOSE_BUY_PROFIT (m_language==RUSSIAN ? "Закрыть BUY прибыльные" : "Close BUY Profit") #define CLOSE_SELL_PROFIT (m_language==RUSSIAN ? "Закрыть SELL прибыльные" : "Close SELL Profit") #define CLOSE_ALL_PROFIT (m_language==RUSSIAN ? "Закрыть ВСЕ прибыльные" : "Close ALL Profit") #define CLOSE_BUY_LOSS (m_language==RUSSIAN ? "Закрыть BUY убыточные" : "Close BUY Losing") #define CLOSE_SELL_LOSS (m_language==RUSSIAN ? "Закрыть SELL убыточные" : "Close SELL Losing") #define CLOSE_ALL_LOSS (m_language==RUSSIAN ? "Закрыть ВСЕ убыточные" : "Close ALL Losing")
プロジェクトをコンパイルして中間結果を確認します。
図7 ボタンとモードスイッチの追加
しかし、これは視覚的な実装にすぎません。次の手順は、追加された要素ごとに論理タスクを割り当てることです。後続のすべての要素はそれらの値と状態を参照するため、切り替えメカニズムを設定しましょう。ボタンオブジェクトの新しいModeButtonSwitch()メソッドを作成します。ボタンを押すとモードが切り替わります。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::ModeButtonSwitch(CButton &button,long lparam,string &states[]) { if(lparam==button.Id()) { int size=ArraySize(states); for(int i=0; i<size; i++) { if(button.LabelText()==states[i]) { if(i==size-1) { SetButtonParam(button,states[0]); break; } else { SetButtonParam(button,states[i+1]); break; } } } } }
別の新しいModeEditSwitch()メソッドは、入力フィールド設定と選択したモードの対応を提供します。たとえば、ポイントは整数であり、預金通貨を使用する場合、値は小数点以下2桁である必要があります。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::ModeEditSwitch(long lparam,string &states[]) { for(int i=0; i<6; i++) { if(lparam==m_mode_button[i].Id()) { if(m_mode_button[i].LabelText()==states[1]) { m_mode_edit[i].IsLocked(false); m_mode_edit[i].SetDigits(0); m_mode_edit[i].StepValue(1); m_mode_edit[i].MaxValue(9999); m_mode_edit[i].MinValue(1); m_mode_edit[i].SetValue(string(20)); m_mode_edit[i].GetTextBoxPointer().Update(true); m_current_mode[i]=1; } else if(m_mode_button[i].LabelText()==states[2]) { m_mode_edit[i].IsLocked(false); m_mode_edit[i].SetDigits(2); m_mode_edit[i].StepValue(0.01); m_mode_edit[i].MaxValue(99999); m_mode_edit[i].MinValue(0.01); m_mode_edit[i].SetValue(string(0.1)); m_mode_edit[i].GetTextBoxPointer().Update(true); m_current_mode[i]=2; } else if(m_mode_button[i].LabelText()==states[3]) { m_mode_edit[i].IsLocked(false); m_mode_edit[i].SetDigits(0); m_mode_edit[i].StepValue(1); m_mode_edit[i].MaxValue(9999); m_mode_edit[i].MinValue(1); m_mode_edit[i].SetValue(string(20)); m_mode_edit[i].GetTextBoxPointer().Update(true); m_current_mode[i]=3; } else if(m_mode_button[i].LabelText()==states[4]) { m_mode_edit[i].IsLocked(false); m_mode_edit[i].SetDigits(2); m_mode_edit[i].StepValue(0.01); m_mode_edit[i].MaxValue(99999); m_mode_edit[i].MinValue(0.01); m_mode_edit[i].SetValue(string(0.1)); m_mode_edit[i].GetTextBoxPointer().Update(true); m_current_mode[i]=4; } else { m_mode_edit[i].IsLocked(true); m_current_mode[i]=0; } } } }
現在の実装には静的配列m_current_modeがあり、そのサイズはモード切り替えボタンの数(6)に対応します。ユーザーが選択した各決済ボタンのモードは、この配列に書き込まれます。新しく追加されたメソッドをアクティブにするには、OnEvent()イベントハンドラを開き、ボタンクリックイベントに次のコードを追加します。
//--- string states[5]= {"all",">points",">currency","sum>points","sum>currency"}; for(int i=0; i<6; i++) ModeButtonSwitch(m_mode_button[i],lparam,states); //--- ModeEditSwitch(lparam,states);
プロジェクトをコンパイルします。これで、モードの切り替えによって入力フィールドのプロパティが変更されます。これを図8に示します。
図8 成立ポジション決済モードの切り替え
次の手順は、ボタンの説明に従ってアクションロジックを実装することです。これは、以前に追加されたモードにもリンクする必要があります。すでに「すべて利益を伴うポジションを決済」と「すべての損失を伴うポジションを決済」の2つのアクションがありますが、新しい決済モードに従って拡張されるべきです。これらのアクションは、CloseAllMarketProfit()メソッドおよびCloseAllMarketLoss()メソッドによって実行されます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseAllMarketProfit(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[2].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_C)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate profit for modes 4 and 5 if(m_current_mode[0]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- int profit_pp; if(type==POSITION_TYPE_BUY) profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); else profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) { switch(m_current_mode[0]) { case 3: sum_pp+=profit_pp; break; case 4: sum_cur+=profit_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); int profit_pp; //--- if(type==POSITION_TYPE_BUY) profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); else profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); //--- if MagicNumber matches if(magic==m_magic_number) if(position_symbol==Symbol()) { if( (m_current_mode[0]==0 && profit_cur+swap>0) || // Close all profitable positions (m_current_mode[0]==1 && profit_pp>int(m_mode_edit[0].GetValue())) || // Close all positions having profit more than N points (m_current_mode[0]==2 && profit_cur+swap>double(m_mode_edit[0].GetValue())) || // Close all positions having profit more than N deposit currency units (m_current_mode[0]==3 && sum_pp>int(m_mode_edit[0].GetValue())) || // Close all positions with the total profit more than N points (m_current_mode[0]==4 && sum_cur>double(m_mode_edit[0].GetValue())) // Close all positions with the total profit more than N deposit currency units ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_DEAL; // trading operation type request.position =position_ticket; // position ticket request.symbol =position_symbol; // symbol request.volume =volume; // position volume request.deviation=5; // allowable price deviation request.magic =m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type if(type==POSITION_TYPE_BUY) { request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID); request.type =ORDER_TYPE_SELL; } else { request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK); request.type =ORDER_TYPE_BUY; } //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } }
これは、すべての成行ポジションを決済するメソッドの変更です。以前、ボタンの各アクションのモード選択を追跡するm_current_mode静的配列を導入しました。したがって、モード4および5について計算が行われます。このモードでは、すべてのポジションがポイントまたは預金通貨での総利益によって決済されます。その後、ツールキットに属するポジションを選択し、選択した決済モードに応じて、条件を選択し、ツールキットによって作成されたすべての成行ポジションを決済する必要があります。
同様に、すべての負けポジションを閉じる2番目のメソッドを変更します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseAllMarketLoss(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[6].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_D)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; ZeroMemory(request); ZeroMemory(result); int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate losses if(m_current_mode[3]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double loss_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); int loss_pp; //--- if(type==POSITION_TYPE_BUY) loss_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); else loss_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) { switch(m_current_mode[3]) { case 3: sum_pp+=loss_pp; break; case 4: sum_cur+=loss_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double loss_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); int loss_pp; if(type==POSITION_TYPE_BUY) loss_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); else loss_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); //--- if MagicNumber matches if(magic==m_magic_number) if(position_symbol==Symbol()) { if( (m_current_mode[3]==0 && loss_cur+swap<0) || (m_current_mode[3]==1 && loss_pp<-int(m_mode_edit[3].GetValue())) || (m_current_mode[3]==2 && loss_cur+swap<-double(m_mode_edit[3].GetValue())) || (m_current_mode[3]==3 && sum_pp<-int(m_mode_edit[3].GetValue())) || (m_current_mode[3]==4 && sum_cur<-double(m_mode_edit[3].GetValue())) ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action=TRADE_ACTION_DEAL; // trading operation type request.position=position_ticket; // position ticket request.symbol=position_symbol; // symbol request.volume=volume; // position volume request.deviation=5; // allowable price deviation request.magic=m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type if(type==POSITION_TYPE_BUY) { request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID); request.type =ORDER_TYPE_SELL; } else { request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK); request.type =ORDER_TYPE_BUY; } //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } }
また、計算はポイントまたは預金通貨でのすべてのポジションの合計損失が確認されるモードに対して実行され、適切な損失条件があれば、ツールキットによって作成されたすべての成行ポジションが決済されます。
それでは、ポジションでの新しいアクションに移りましょう。勝ち/負け、買い/売りポジションを決済することです。実際、これらは上記の2つのメソッドの特殊なケースです。したがって、ポジションタイプによるフィルタリングを追加します。まず、指定されたアクションを実行するメソッドを作成します。
- CloseBuyMarketProfit() — すべての勝ち/買いポジションを決済
- CloseSellMarketProfit() — すべての勝ち/売りポジションを決済
- CloseBuyMarketLoss() — すべての負け/買いポジションを決済
- CloseSellMarketLoss() — すべての勝ち/売りポジションを決済
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseBuyMarketProfit(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[4].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_U)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate profit for modes 4 and 5 if(m_current_mode[1]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_BUY) { int profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); switch(m_current_mode[1]) { case 3: sum_pp+=profit_pp; break; case 4: sum_cur+=profit_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_BUY) { int profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); if( (m_current_mode[1]==0 && profit_cur+swap>0) || // Close all profitable positions (m_current_mode[1]==1 && profit_pp>int(m_mode_edit[1].GetValue())) || // Close all positions having profit more than N points (m_current_mode[1]==2 && profit_cur+swap>double(m_mode_edit[1].GetValue())) || // Close all positions having profit more than N deposit currency units (m_current_mode[1]==3 && sum_pp>int(m_mode_edit[1].GetValue())) || // Close all positions with the total profit more than N points (m_current_mode[1]==4 && sum_cur>double(m_mode_edit[1].GetValue())) // Close all positions with the total profit more than N deposit currency units ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_DEAL; // trading operation type request.position =position_ticket; // position ticket request.symbol =position_symbol; // symbol request.volume =volume; // position volume request.deviation=5; // allowable price deviation request.magic =m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID); request.type =ORDER_TYPE_SELL; //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseBuyMarketLoss(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[7].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_H)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate profit for modes 4 and 5 if(m_current_mode[4]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_BUY) { int profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); switch(m_current_mode[1]) { case 3: sum_pp+=profit_pp; break; case 4: sum_cur+=profit_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_BUY) { int profit_pp=int((SymbolInfoDouble(position_symbol,SYMBOL_BID)-PositionGetDouble(POSITION_PRICE_OPEN))/_Point); if( (m_current_mode[4]==0 && profit_cur+swap<0) || // Close all profitable positions (m_current_mode[4]==1 && profit_pp<-int(m_mode_edit[4].GetValue())) || // Close all positions having profit more than N points (m_current_mode[4]==2 && profit_cur+swap<-double(m_mode_edit[4].GetValue())) || // Close all positions having profit more than N deposit currency units (m_current_mode[4]==3 && sum_pp<-int(m_mode_edit[4].GetValue())) || // Close all positions with the total profit more than N points (m_current_mode[4]==4 && sum_cur<-double(m_mode_edit[4].GetValue())) // Close all positions with the total profit more than N deposit currency units ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_DEAL; // trading operation type request.position =position_ticket; // position ticket request.symbol =position_symbol; // symbol request.volume =volume; // position volume request.deviation=5; // allowable price deviation request.magic =m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID); request.type =ORDER_TYPE_SELL; //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseSellMarketProfit(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[5].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_J)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate profit for modes 4 and 5 if(m_current_mode[2]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_SELL) { int profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); switch(m_current_mode[2]) { case 3: sum_pp+=profit_pp; break; case 4: sum_cur+=profit_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_SELL) { int profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); if( (m_current_mode[2]==0 && profit_cur+swap>0) || // Close all profitable positions (m_current_mode[2]==1 && profit_pp>int(m_mode_edit[2].GetValue())) || // Close all positions having profit more than N points (m_current_mode[2]==2 && profit_cur+swap>double(m_mode_edit[2].GetValue())) || // Close all positions having profit more than N deposit currency units (m_current_mode[2]==3 && sum_pp>int(m_mode_edit[2].GetValue())) || // Close all positions with the total profit more than N points (m_current_mode[2]==4 && sum_cur>double(m_mode_edit[2].GetValue())) // Close all positions with the total profit more than N deposit currency units ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_DEAL; // trading operation type request.position =position_ticket; // position ticket request.symbol =position_symbol; // symbol request.volume =volume; // position volume request.deviation=5; // allowable price deviation request.magic =m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK); request.type =ORDER_TYPE_BUY; //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::CloseSellMarketLoss(int id,long lparam) { if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[8].Id()) || (id==CHARTEVENT_KEYDOWN && lparam==KEY_L)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; int total=PositionsTotal(); // the number of open positions int sum_pp=0; double sum_cur=0.0; //--- Calculate profit for modes 4 and 5 if(m_current_mode[5]>2) { for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_SELL) { int profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); switch(m_current_mode[1]) { case 3: sum_pp+=profit_pp; break; case 4: sum_cur+=profit_cur+swap; break; } } } } //--- iterate over open positions for(int i=total-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double profit_cur=PositionGetDouble(POSITION_PROFIT); double swap=PositionGetDouble(POSITION_SWAP); //--- if(magic==m_magic_number) if(position_symbol==Symbol()) if(type==POSITION_TYPE_SELL) { int profit_pp=int((PositionGetDouble(POSITION_PRICE_OPEN)-SymbolInfoDouble(position_symbol,SYMBOL_ASK))/_Point); if( (m_current_mode[5]==0 && profit_cur+swap<0) || // Close all profitable positions (m_current_mode[5]==1 && profit_pp<-int(m_mode_edit[5].GetValue())) || // Close all positions having profit more than N points (m_current_mode[5]==2 && profit_cur+swap<-double(m_mode_edit[5].GetValue())) || // Close all positions having profit more than N deposit currency units (m_current_mode[5]==3 && sum_pp<-int(m_mode_edit[5].GetValue())) || // Close all positions with the total profit more than N points (m_current_mode[5]==4 && sum_cur<-double(m_mode_edit[5].GetValue())) // Close all positions with the total profit more than N deposit currency units ) { //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_DEAL; // trading operation type request.position =position_ticket; // position ticket request.symbol =position_symbol; // symbol request.volume =volume; // position volume request.deviation=5; // allowable price deviation request.magic =m_magic_number; // position MagicNumber //--- Set order price and type depending on the position type request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK); request.type =ORDER_TYPE_BUY; //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) break; else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } } } }
実装したら、セクションなしでOnEvent()イベントハンドラ本体のメソッドを呼び出します。
//---
CloseBuyMarketProfit(id,lparam);
CloseSellMarketProfit(id,lparam);
CloseBuyMarketLoss(id,lparam);
CloseSellMarketLoss(id,lparam);
各アクションは、ボタンクリックだけでなく、キー押下イベントによっても実行できます。コードでホットキーを再割り当てできます。便宜上、ボタンのアクション名の横に値を表示します。
//--- if(!CreateButton(m_order_button[0],MARKET_ORDER_NAME+"(M)",C'87,128,255',10,10)) return(false); if(!CreateButton(m_order_button[1],PENDING_ORDER_NAME+"(P)",C'31,209,111',300,10)) return(false); if(!CreateButton(m_order_button[2],CLOSE_ALL_PROFIT+"(C)",C'87,128,255',10,10+45*1)) return(false); if(!CreateButton(m_order_button[3],PEND_ORDERS_ALL_CLOSE+"(R)",C'31,209,111',300,10+45*1)) return(false); if(!CreateButton(m_order_button[4],CLOSE_BUY_PROFIT+"(U)",C'87,128,255',10,10+45*2)) return(false); if(!CreateButton(m_order_button[5],CLOSE_SELL_PROFIT+"(J)",C'87,128,255',10,10+45*3)) return(false); if(!CreateButton(m_order_button[6],CLOSE_ALL_LOSS+"(D)",C'87,128,255',10,10+45*4)) return(false); if(!CreateButton(m_order_button[7],CLOSE_BUY_LOSS+"(H)",C'87,128,255',10,10+45*5)) return(false); if(!CreateButton(m_order_button[8],CLOSE_SELL_LOSS+"(L)",C'87,128,255',10,10+45*6)) return(false);
その結果、次の値が得られます。
図9 追加されたアクションへのホットキーの割り当て
[Trading](取引)タブのすべての機能を実装しました。それでは、次の段階に進みましょう。ツールキットによって開かれたポジションの表を作成し、[Market Positions Control](成行ポジションコントロール)タブでポジションを管理する可能性を追加します。本稿冒頭の図3には、3つの入力フィールド、2つのボタン、および表で構成されるインターフェイス要素を作成するための視覚的なスキームが含まれています。タブの作成を始めましょう。まず、ロットを編集するための3つの入力フィールド、ポジションのストップロスとテイクプロフィットを作成します。これらは、CreateLotControl()、CreateStopLossControl()、CreateTakeProfitControl()メソッドで実行されます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateLotControl(CTextEdit &text_edit,const int x_gap,const int y_gap,int tab) { //--- Store the pointer to the main control text_edit.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(tab,text_edit); //--- Properties text_edit.XSize(80); text_edit.YSize(24); text_edit.Font(m_base_font); text_edit.FontSize(m_base_font_size); text_edit.MaxValue(9999); text_edit.StepValue(_Point); text_edit.SetDigits(_Digits); text_edit.SpinEditMode(true); text_edit.GetTextBoxPointer().XGap(1); text_edit.GetTextBoxPointer().XSize(80); //--- Create a control element if(!text_edit.CreateTextEdit("",x_gap,y_gap)) return(false); text_edit.SetValue(string(0)); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,text_edit); return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateTakeProfitControl(CTextEdit &text_edit,const int x_gap,const int y_gap,int tab) { //--- Store the pointer to the main control text_edit.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(tab,text_edit); //--- Properties text_edit.XSize(80); text_edit.YSize(24); text_edit.Font(m_base_font); text_edit.FontSize(m_base_font_size); text_edit.MaxValue(9999); text_edit.StepValue(_Point); text_edit.SetDigits(_Digits); text_edit.SpinEditMode(true); text_edit.GetTextBoxPointer().XGap(1); text_edit.GetTextBoxPointer().XSize(80); //--- Create a control element if(!text_edit.CreateTextEdit("",x_gap,y_gap)) return(false); text_edit.SetValue(string(0)); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,text_edit); return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateStopLossControl(CTextEdit &text_edit,const int x_gap,const int y_gap,int tab) { //--- Store the pointer to the main control text_edit.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(tab,text_edit); //--- Properties text_edit.XSize(80); text_edit.YSize(24); text_edit.Font(m_base_font); text_edit.FontSize(m_base_font_size); text_edit.MaxValue(9999); text_edit.StepValue(_Point); text_edit.SetDigits(_Digits); text_edit.MinValue(0); text_edit.SpinEditMode(true); text_edit.GetTextBoxPointer().XGap(1); text_edit.GetTextBoxPointer().XSize(80); //--- Create a control element if(!text_edit.CreateTextEdit("",x_gap,y_gap)) return(false); text_edit.SetValue(string(0)); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,text_edit); return(true); }
CreateMainWindow()本体に新しいメソッドを追加します。
//--- Input field for editing open positions if(!CreateLotControl(m_lot_edit[6],375,3,1)) return(false); if(!CreateStopLossControl(m_sl_edit[6],375+80,3,1)) return(false); if(!CreateTakeProfitControl(m_tp_edit[6],375+83*2,3,1)) return(false);
[Edit](編集)および[Close](決済)ボタンでは、新しいCreateModifyButton()メソッドおよびCreateCloseButton()メソッドを作成して実装するべきです。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateModifyButton(CButton &button,string text,int x_gap,int y_gap,int tab) { //--- Store the window pointer button.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(tab,button); color baseclr=clrDarkOrange; color pressclr=clrOrange; //--- Set properties before creation button.XSize(80); button.YSize(24); button.Font(m_base_font); button.FontSize(m_base_font_size); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(pressclr); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(pressclr); button.LabelColor(clrWhite); button.LabelColorPressed(clrWhite); button.LabelColorHover(clrWhite); button.IsCenterText(true); //--- Create a control element if(!button.CreateButton(text,x_gap,y_gap)) return(false); //--- Add a pointer to the element to the database CWndContainer::AddToElementsArray(0,button); return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::CreateCloseButton(CButton &button,string text,int x_gap,int y_gap,int tab) { //--- Store the window pointer button.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(tab,button); color baseclr=clrCrimson; color pressclr=clrFireBrick; //--- Set properties before creation button.XSize(80); button.YSize(24); button.Font(m_base_font); button.FontSize(m_base_font_size); button.BackColor(baseclr); button.BackColorHover(baseclr); button.BackColorPressed(pressclr); button.BorderColor(baseclr); button.BorderColorHover(baseclr); button.BorderColorPressed(pressclr); button.LabelColor(clrWhite); button.LabelColorPressed(clrWhite); button.LabelColorHover(clrWhite); button.IsCenterText(true); //--- Create a control element if(!button.CreateButton(text,x_gap,y_gap)) return(false); //--- Add a pointer to the element to the database CWndContainer::AddToElementsArray(0,button); return(true); }
メインウィンドウ作成メソッドに作成します。
//--- Position editing/closing buttons if(!CreateModifyButton(m_small_button[0],MODIFY,622,3,1)) return(false); if(!CreateCloseButton(m_small_button[1],CLOSE,622+80,3,1)) return(false);
ここでは、UIローカリゼーション用の2つの新しいマクロ置換があるため、Defines.mqhを開き、適切な値を追加します。
#define MODIFY (m_language==RUSSIAN ? "Изменить" : "Modify") #define CLOSE (m_language==RUSSIAN ? "Закрыть" : "Close")
ここで、表に移ります。まずCreatePositionsTable()メソッドを作成し、実装して、メインウィンドウメソッドに追加します。
//+------------------------------------------------------------------+ //| Create a table of positions | //+------------------------------------------------------------------+ bool CFastTrading::CreatePositionsTable(CTable &table,const int x_gap,const int y_gap) { #define COLUMNS2_TOTAL 9 //--- Store the pointer to the main control table.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(1,table); //--- Array of column widths int width[COLUMNS2_TOTAL]; ::ArrayInitialize(width,80); width[0]=100; width[1]=110; width[2]=100; width[3]=60; width[6]=90; //--- Array of text alignment in columns ENUM_ALIGN_MODE align[COLUMNS2_TOTAL]; ::ArrayInitialize(align,ALIGN_CENTER); //--- Array of text offset along the X axis in the columns int text_x_offset[COLUMNS2_TOTAL]; ::ArrayInitialize(text_x_offset,7); //--- Array of column image offsets along the X axis int image_x_offset[COLUMNS2_TOTAL]; ::ArrayInitialize(image_x_offset,3); //--- Array of column image offsets along the Y axis int image_y_offset[COLUMNS2_TOTAL]; ::ArrayInitialize(image_y_offset,2); //--- Properties table.Font(m_base_font); table.FontSize(m_base_font_size); table.XSize(782); table.CellYSize(24); table.TableSize(COLUMNS2_TOTAL,1); table.TextAlign(align); table.ColumnsWidth(width); table.TextXOffset(text_x_offset); table.ImageXOffset(image_x_offset); table.ImageYOffset(image_y_offset); table.ShowHeaders(true); table.HeadersColor(C'87,128,255'); table.HeadersColorHover(clrCornflowerBlue); table.HeadersTextColor(clrWhite); table.IsSortMode(false); table.LightsHover(true); table.SelectableRow(true); table.IsZebraFormatRows(clrWhiteSmoke); table.DataType(0,TYPE_LONG); table.AutoYResizeMode(true); table.AutoYResizeBottomOffset(5); //--- Create a control element if(!table.CreateTable(x_gap,y_gap)) return(false); //--- Set the header titles table.SetHeaderText(0,TICKET); table.SetHeaderText(1,SYMBOL); table.SetHeaderText(2,TYPE_POS); table.SetHeaderText(3,PRICE); table.SetHeaderText(4,VOLUME); table.SetHeaderText(5,SL); table.SetHeaderText(6,TP); table.SetHeaderText(7,SWAP); table.SetHeaderText(8,PROFIT); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,table); return(true); }
表には9つの列があります。列名の長さが異なるため、列幅を調整します。Defines.mqhファイルのマクロ置換を使用して、使用可能な2つの言語の列名を設定します。
#define SYMBOL (m_language==RUSSIAN ? "Символ" : "Symbol") #define VOLUME (m_language==RUSSIAN ? "Объем" : "Volume") #define TYPE_POS (m_language==RUSSIAN ? "Тип позиции" : "Position Type") #define SWAP (m_language==RUSSIAN ? "Своп" : "Swap") #define PROFIT (m_language==RUSSIAN ? "Прибыль" : "Profit")
ただし、今すぐプロジェクトをコンパイルしようとすると、表、ボタン、フィールドがウィンドウの右端を超えていることがわかります。そのため、内容に応じてメインウィンドウの幅を調整するメカニズムを追加する必要があります。これは、WindowRezise()メソッドで実行できます。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::WindowResize(int x_size,int y_size) { m_main_window.GetCloseButtonPointer().Hide(); m_main_window.ChangeWindowWidth(x_size); m_main_window.ChangeWindowHeight(y_size); m_main_window.GetCloseButtonPointer().Show(); }
イベントハンドラで、新しいタブクリックイベントを作成します。このイベントでは、各タブのメインウィンドウの幅を追加します。
//--- Tab switching event if(id==CHARTEVENT_CUSTOM+ON_CLICK_TAB) { if(m_tab.SelectedTab()==0) WindowResize(600,m_main_window.YSize()); if(m_tab.SelectedTab()==1) WindowResize(782+10,m_main_window.YSize()); if(m_tab.SelectedTab()==2) WindowResize(682+10,m_main_window.YSize()); }
これで、図3に示すように、情報が正しく表示されます。次の手順は、アプリケーションによって開かれたポジションに関するデータを受け取り、作成された表にこの情報を表示することです。表にデータを準備して表示するには、次の3つの手順があります。
- 初期化: ここでは、ツールキットに属するポジションの数を決定し、このデータの表を再構築します。
- データの追加: 列ヘッダーの説明に従って、各ポジションのパラメータを表に追加します。
- 入力されたデータで表を更新します。
最初の初期化手順では、InitializePositionsTable()関数を作成し、現在の銘柄とマジックナンバーですべてのポジションを選択します。このようにして、条件を満たすポジションの数を取得します。同じ数の行を表に追加します。
//+------------------------------------------------------------------+ //| Initializing the table of positions | //+------------------------------------------------------------------+ void CFastTrading::InitializePositionsTable(void) { //--- Get symbols of open positions int total=PositionsTotal(); // the number of open positions int cnt=0; //--- Delete all rows m_table_positions.DeleteAllRows(); //--- Set the number of rows equal to the number of positions for(int i=0; i<total; i++) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber //--- if MagicNumber matches if(magic==m_magic_number) if(position_symbol==Symbol()) { m_table_positions.AddRow(cnt); cnt++; } } //--- If there are positions if(cnt>0) { //--- Set the values in the table SetValuesToPositionsTable(); //--- Update the table UpdatePositionsTable(); } }
次に、ツールキットによって開かれたポジションが少なくとも1つあるかどうかを確認します。そのようなポジションがある場合は、SetValuePositionTable()メソッドを使用して、新しく作成された行のポジションに関する情報を設定します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::SetValuesToPositionsTable(void) { //--- int cnt=0; for(int i=PositionsTotal()-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // the number of decimal places ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double volume=PositionGetDouble(POSITION_VOLUME); // position volume ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type double stoploss=PositionGetDouble(POSITION_SL); double takeprofit=PositionGetDouble(POSITION_TP); double swap=PositionGetDouble(POSITION_SWAP); double profit=PositionGetDouble(POSITION_PROFIT); double openprice=PositionGetDouble(POSITION_PRICE_OPEN); string pos=(type==POSITION_TYPE_BUY)?"BUY":"SELL"; profit+=swap; //--- if MagicNumber matches if(magic==m_magic_number) if(position_symbol==Symbol()) { m_table_positions.SetValue(0,i,string(position_ticket)); m_table_positions.SetValue(1,i,string(position_symbol)); m_table_positions.SetValue(2,i,pos); m_table_positions.SetValue(3,i,string(openprice)); m_table_positions.SetValue(4,i,string(volume)); m_table_positions.SetValue(5,i,string(stoploss)); m_table_positions.SetValue(6,i,string(takeprofit)); m_table_positions.SetValue(7,i,string(swap)); m_table_positions.SetValue(8,i,DoubleToString(profit,2)); //--- m_table_positions.TextColor(2,i,(pos=="BUY")? clrForestGreen : clrCrimson); m_table_positions.TextColor(8,i,(profit!=0)? (profit>0)? clrForestGreen : clrCrimson : clrSilver); cnt++; } } }
データを入力した後、UpdatePositionsTable()を使用して表を更新します。
//+------------------------------------------------------------------+ //| Update the table of positions | //+------------------------------------------------------------------+ void CFastTrading::UpdatePositionsTable(void) { //--- Update the table m_table_positions.Update(true); m_table_positions.GetScrollVPointer().Update(true); }
製品の変更を有効にするには、それらを適切に構成する必要があります。SimpleTrading.mq5ファイルを開き、OnInit()関数を見つけて、アプリケーションクラスを初期化するメソッドの呼び出しを追加します。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- Initialize class variables program.FontName("Trebuchet MS"); program.FontSize(Inp_BaseFont); program.BackgroundColor(Background); program.CaptionColor(Caption); program.SetLanguage(Language); program.SetMagicNumber(MagicNumber); //--- Set up the trading panel if(!program.CreateGUI()) { Print(__FUNCTION__," > Failed to create graphical interface!"); return(INIT_FAILED); } program.OnInitEvent(); //--- return(INIT_SUCCEEDED); }
これは、CreateGUI()でアプリケーションGUIを作成した後に厳密に実行する必要があります。次に、OnInitEvent()本体に移動し、その中で表の初期化を呼び出します。
//+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ void CFastTrading::OnInitEvent(void) { InitializePositionsTable(); }
これで、表にポジションに関する情報が正しく表示されます。ただし、このデータはアプリケーションの起動時にのみ関連するため、常に更新する必要があります。これは、OnTrade()取引イベントハンドラとOnTick()関数で実行する必要があります。取引イベントでは、現在のポジションの数とそのパラメータを追跡します。各注文の現在の利益に関する情報は、OnTickで更新されます。
基本クラスのpublicセクションにOnTradeEvent()メソッドを作成して、本体で表の初期化を呼び出します。
//+------------------------------------------------------------------+ //| Trade event | //+------------------------------------------------------------------+ void CFastTrading::OnTradeEvent(void) { //--- If a new trade InitializePositionsTable(); }
新しいメソッドは取引イベントハンドラで呼び出されます。
//+------------------------------------------------------------------+ //| Trade function | //+------------------------------------------------------------------+ void OnTrade(void) { program.OnTradeEvent(); }
上記のアクションは、表示されたポジションの関連性を設定します。利益を更新するには、CFastTradingクラスのpublicセクションにUpdatePositionProfit()メソッドを作成します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::UpdatePositionProfit(void) { //--- int cnt=0; for(int i=PositionsTotal()-1; i>=0; i--) { //--- order parameters ulong position_ticket=PositionGetTicket(i); // position ticket string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol ulong magic=PositionGetInteger(POSITION_MAGIC); // position MagicNumber double swap=PositionGetDouble(POSITION_SWAP); double profit=PositionGetDouble(POSITION_PROFIT); profit+=swap; //--- if MagicNumber matches if(magic==m_magic_number) if(position_symbol==Symbol()) { m_table_positions.SetValue(8,i,DoubleToString(profit,2)); //--- m_table_positions.TextColor(8,i,(profit!=0)? (profit>0)? clrForestGreen : clrCrimson : clrSilver); cnt++; } } //--- if(cnt>0) UpdatePositionsTable(); }
OnTick()で呼び出します。
void OnTick() { program.UpdatePositionProfit(); }
これで表の実装は完了です。次に、現在のリストで利用可能なポジションを編集して決済する可能性を作成しましょう。表の行をクリックすると入力フィールドに選択したポジションのロット、テイクプロフィット、ストップロスが表示されるようにします。
//--- Event of clicking on a table row if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM) { //--- Check the element ID if(lparam==m_table_positions.Id()) { //--- int row=m_table_positions.SelectedItem(); m_lot_edit[6].SetValue(string(m_table_positions.GetValue(4,row))); m_sl_edit[6].SetValue(string(m_table_positions.GetValue(5,row))); m_tp_edit[6].SetValue(string(m_table_positions.GetValue(6,row))); m_lot_edit[6].GetTextBoxPointer().Update(true); m_sl_edit[6].GetTextBoxPointer().Update(true); m_tp_edit[6].GetTextBoxPointer().Update(true); } }
プロジェクトをコンパイルすると、結果は図10(入力フィールドに表示される選択した成行ポジションからの値)に示すようになります。
図10 さらに編集するための開いたポジションの選択
次に、ModifyPosition()とClosePosition()の2つのメソッドを作成します。[Modify](変更)ボタンと[Close](決済)ボタンをクリックすると、メソッドは選択したポジションに適切なアクションを適用します。
//+------------------------------------------------------------------+ //| Modifying a selected open position | //+------------------------------------------------------------------+ bool CFastTrading::ModifyPosition(long lparam) { //--- Check the element ID if(lparam==m_small_button[0].Id()) { //--- Get index and symbol if(m_table_positions.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_positions.SelectedItem(); ulong ticket=(ulong)m_table_positions.GetValue(0,row); //--- if(PositionSelectByTicket(ticket)) { //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- calculation and rounding of the Stop Loss and Take Profit values double sl=NormalizeDouble((double)m_sl_edit[6].GetValue(),_Digits); double tp=NormalizeDouble((double)m_tp_edit[6].GetValue(),_Digits); //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action =TRADE_ACTION_SLTP; // trading operation type request.position=ticket; // position ticket request.symbol=Symbol(); // symbol request.sl =sl; // position Stop Loss request.tp =tp; // position Take Profit request.magic=m_magic_number; // position MagicNumber //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::ClosePosition(long lparam) { //--- Check the element ID if(lparam==m_small_button[1].Id()) { //--- Get index and symbol if(m_table_positions.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_positions.SelectedItem(); ulong ticket=(ulong)m_table_positions.GetValue(0,row); //--- if(PositionSelectByTicket(ticket)) { ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // position type string position_symbol=PositionGetString(POSITION_SYMBOL); // symbol //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- Set order price and type depending on the position type if(type==POSITION_TYPE_BUY) { request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID); request.type =ORDER_TYPE_SELL; } else if(type==POSITION_TYPE_SELL) { request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK); request.type =ORDER_TYPE_BUY; } //--- check volume double position_volume=PositionGetDouble(POSITION_VOLUME); double closing_volume=(double)m_lot_edit[6].GetValue(); if(closing_volume>position_volume) closing_volume=position_volume; //--- setting request request.action =TRADE_ACTION_DEAL; request.position =ticket; request.symbol =Symbol(); request.volume =NormalizeLot(Symbol(),closing_volume); request.magic =m_magic_number; request.deviation=5; //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); }
これで、[Market PositionsControl](成行ポジションコントロール)タブでのタスクの実装が完了しました。[Pending Orders Control](指値注文の管理)タブの開発に移ります。CreateMainWindow()メインウィンドウメソッド本体の最後に、前のタブで実装したのと同じ機能(指値注文の表、注文を編集するためのボタンと入力フィールド)を追加するコードを追加します。
//--- Create a table of pending orders if(!CreateOrdersTable(m_table_orders,0,22+5)) return(false); //--- Input fields for editing pending orders if(!CreateLotControl(m_pr_edit[4],360,3,2)) return(false); if(!CreateStopLossControl(m_sl_edit[7],360+80,3,2)) return(false); if(!CreateTakeProfitControl(m_tp_edit[7],360+80*2,3,2)) return(false); //--- Pending order modifying/deleting orders if(!CreateModifyButton(m_small_button[2],MODIFY,361+80*3,3,2)) return(false); if(!CreateCloseButton(m_small_button[3],REMOVE,361+80*3,3+24,2)) return(false);
この追加には、指値注文の表を追加する新しいメソッドと、注文削除ボタンの新しいマクロ置換があります。表がどのように作成されるかを詳しく見てみましょう。
//+------------------------------------------------------------------+ //| Creates a table of pending orders | //+------------------------------------------------------------------+ //--- bool CFastTrading::CreateOrdersTable(CTable &table,const int x_gap,const int y_gap) { #define COLUMNS1_TOTAL 7 //--- Store the pointer to the main control table.MainPointer(m_tab); //--- Attach to tab m_tab.AddToElementsArray(2,table); //--- Array of column widths int width[COLUMNS1_TOTAL]; ::ArrayInitialize(width,80); width[0]=100; width[2]=100; //--- Array of text offset along the X axis in the columns int text_x_offset[COLUMNS1_TOTAL]; ::ArrayInitialize(text_x_offset,7); //--- Array of column image offsets along the X axis int image_x_offset[COLUMNS1_TOTAL]; ::ArrayInitialize(image_x_offset,3); //--- Array of column image offsets along the Y axis int image_y_offset[COLUMNS1_TOTAL]; ::ArrayInitialize(image_y_offset,2); //--- Array of text alignment in columns ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]; ::ArrayInitialize(align,ALIGN_CENTER); align[6]=ALIGN_LEFT; //--- Properties table.Font(m_base_font); table.FontSize(m_base_font_size); table.XSize(602); table.CellYSize(24); table.TableSize(COLUMNS1_TOTAL,1); table.TextAlign(align); table.ColumnsWidth(width); table.TextXOffset(text_x_offset); table.ImageXOffset(image_x_offset); table.ImageYOffset(image_x_offset); table.ShowHeaders(true); table.HeadersColor(C'87,128,255'); table.HeadersColorHover(clrCornflowerBlue); table.HeadersTextColor(clrWhite); table.IsSortMode(false); table.LightsHover(true); table.SelectableRow(true); table.IsZebraFormatRows(clrWhiteSmoke); table.AutoYResizeMode(true); table.AutoYResizeBottomOffset(5); table.DataType(0,TYPE_LONG); table.DataType(1,TYPE_STRING); table.DataType(2,TYPE_STRING); table.DataType(3,TYPE_DOUBLE); table.DataType(4,TYPE_DOUBLE); table.DataType(5,TYPE_DOUBLE); //--- Create a control element if(!table.CreateTable(x_gap,y_gap)) return(false); //--- Set the header titles table.SetHeaderText(0,TICKET); table.SetHeaderText(1,SYMBOL); table.SetHeaderText(2,TYPE_POS); table.SetHeaderText(3,VOLUME); table.SetHeaderText(4,PRICE); table.SetHeaderText(5,SL); table.SetHeaderText(6,TP); //--- Add the object to the common array of object groups CWndContainer::AddToElementsArray(0,table); return(true); }
この表には、異なる順序で配置された異なる数の列があります。成行ポジションを編集するとき、ロット、およびテイクプロフィットとストップロスの値を変更できます。指標注文については、ここではロットではなく始値を変更します。プロジェクトをコンパイルし、[Pending Orders Control](指値注文の管理)タブで結果を確認します。
図11 指値注文を処理するためのインターフェイス
さらなる開発は、前のタブで行ったことと同様です。まず、InitializeOrdersTable()を使用して、ツールキットに属するすべての注文を検索します。
//+------------------------------------------------------------------+ //| Initializing the table of positions | //+------------------------------------------------------------------+ void CFastTrading::InitializeOrdersTable(void) { //--- int total=OrdersTotal(); int cnt=0; //--- Delete all rows m_table_orders.DeleteAllRows(); //--- Set the number of rows equal to the number of positions for(int i=0; i<total; i++) { //--- order parameters ulong order_ticket=OrderGetTicket(i); // order ticket string order_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // position MagicNumber //--- if MagicNumber matches if(magic==m_magic_number) if(order_symbol==Symbol()) { m_table_orders.AddRow(cnt); cnt++; } } //--- If there are positions if(cnt>0) { //--- Set the values in the table SetValuesToOrderTable(); //--- Update the table UpdateOrdersTable(); } }
指値注文が見つかった場合は、SetValuesToOrderTable()メソッドを使用して関連情報を表に追加します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::SetValuesToOrderTable(void) { //--- int cnt=0; ulong ticket; for(int i=0; i<OrdersTotal(); i++) { //--- order parameters if((ticket=OrderGetTicket(i))>0) { string position_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // order MagicNumber double volume=OrderGetDouble(ORDER_VOLUME_INITIAL); // order volume ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); // order type double price=OrderGetDouble(ORDER_PRICE_OPEN); double stoploss=OrderGetDouble(ORDER_SL); double takeprofit=OrderGetDouble(ORDER_TP); string pos=""; if(type==ORDER_TYPE_BUY_LIMIT) pos="Buy Limit"; else if(type==ORDER_TYPE_SELL_LIMIT) pos="Sell Limit"; else if(type==ORDER_TYPE_BUY_STOP) pos="Buy Stop"; else if(type==ORDER_TYPE_SELL_STOP) pos="Sell Stop"; //--- if(magic==m_magic_number) if(position_symbol==Symbol()) { m_table_orders.SetValue(0,i,string(ticket)); m_table_orders.SetValue(1,i,string(position_symbol)); m_table_orders.SetValue(2,i,pos); m_table_orders.SetValue(3,i,string(volume)); m_table_orders.SetValue(4,i,string(price)); m_table_orders.SetValue(5,i,string(stoploss)); m_table_orders.SetValue(6,i,string(takeprofit)); cnt++; } } } }
UpdateOrdersTable()メソッドを使用して追加されたデータを更新します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CFastTrading::UpdateOrdersTable(void) { //--- Update the table m_table_orders.Update(true); m_table_orders.GetScrollVPointer().Update(true); }
この機能をアプリケーションに接続するには、前のタブで行ったのと同じ操作をおこないます。つまり、指値注文で表を初期化します。
//+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ void CFastTrading::OnInitEvent(void) { InitializeOrdersTable(); InitializePositionsTable(); }
取引イベントハンドラでアクションを繰り返します。
//+------------------------------------------------------------------+ //| Trade event | //+------------------------------------------------------------------+ void CFastTrading::OnTradeEvent(void) { //--- InitializePositionsTable(); InitializeOrdersTable(); }
表の行をクリックしたときに入力フィールドに関連データを表示できるようにするには、イベントハンドラの適切なセクションに次のコードを追加します。
//--- Event of clicking on a table row if(id==CHARTEVENT_CUSTOM+ON_CLICK_LIST_ITEM) { //--- Check the element ID if(lparam==m_table_positions.Id()) { //--- int row=m_table_positions.SelectedItem(); m_lot_edit[6].SetValue(string(m_table_positions.GetValue(4,row))); m_sl_edit[6].SetValue(string(m_table_positions.GetValue(5,row))); m_tp_edit[6].SetValue(string(m_table_positions.GetValue(6,row))); m_lot_edit[6].GetTextBoxPointer().Update(true); m_sl_edit[6].GetTextBoxPointer().Update(true); m_tp_edit[6].GetTextBoxPointer().Update(true); } //--- Check the element ID if(lparam==m_table_orders.Id()) { //--- int row=m_table_orders.SelectedItem(); m_pr_edit[4].SetValue(string(m_table_orders.GetValue(4,row))); m_sl_edit[7].SetValue(string(m_table_orders.GetValue(5,row))); m_tp_edit[7].SetValue(string(m_table_orders.GetValue(6,row))); m_pr_edit[4].GetTextBoxPointer().Update(true); m_sl_edit[7].GetTextBoxPointer().Update(true); m_tp_edit[7].GetTextBoxPointer().Update(true); } }
次に、関連するアクションを[Modify](変更)ボタンと[Delete](削除)ボタンに割り当てます。ModifyOrder()メソッドとRemoveOrder()を作成します。
//+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::ModifyOrder(long lparam) { //--- Check the element ID if(lparam==m_small_button[2].Id()) { //--- Get index and symbol if(m_table_orders.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_orders.SelectedItem(); ulong ticket=(ulong)m_table_orders.GetValue(0,row); //--- if(OrderSelect(ticket)) { string position_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // order MagicNumber ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); // order type //--- calculation and rounding of the Stop Loss and Take Profit values double sl=NormalizeDouble((double)m_sl_edit[7].GetValue(),_Digits); double tp=NormalizeDouble((double)m_tp_edit[7].GetValue(),_Digits); double price=NormalizeDouble((double)m_pr_edit[4].GetValue(),_Digits); //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action=TRADE_ACTION_MODIFY; // trading operation type request.order = ticket; // order ticket request.symbol=Symbol(); // symbol request.sl =sl; // position Stop Loss request.tp =tp; // position Take Profit request.price=price; // new price request.magic=m_magic_number; // position MagicNumber //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CFastTrading::RemoveOrder(long lparam) { //--- Check the element ID if(lparam==m_small_button[3].Id()) { //--- Get index and symbol if(m_table_orders.SelectedItem()==WRONG_VALUE) return(false); int row=m_table_orders.SelectedItem(); ulong ticket=(ulong)m_table_orders.GetValue(0,row); //--- if(OrderSelect(ticket)) { string position_symbol=OrderGetString(ORDER_SYMBOL); // symbol ulong magic=OrderGetInteger(ORDER_MAGIC); // order MagicNumber ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); // order type //--- declare the request and the result MqlTradeRequest request; MqlTradeResult result; //--- zeroing the request and result values ZeroMemory(request); ZeroMemory(result); //--- set the operation parameters request.action=TRADE_ACTION_REMOVE; // trading operation type request.order = ticket; // order ticket //--- sending a request bool res=true; for(int j=0; j<5; j++) { res=OrderSend(request,result); if(res && result.retcode==TRADE_RETCODE_DONE) return(true); else PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code } } } //--- return(false); }
セクションの外にあるイベントハンドラでそれらを呼び出します。
//--- if(ModifyOrder(lparam)) return; if(RemoveOrder(lparam)) return;
指値注文を処理するための別の便利な機能を追加したいと思います。チャートをクリックすることにより、以前に選択した終了注文の始値を設定する機能を提供します。これを図12に示します。
図12 指値注文の始値の設定
これは次のように機能します。
- 入力フィールドをクリックすると、値の編集がアクティブになります。
- 次に、マウスポインタをチャート上の任意の場所に移動します。適切な値が軸に沿って表示されます。便利なように、マウスホイールをクリックして、十字線を使用して希望の価格を選択できます。
- 希望の価格でマウスポインタを停止し、チャートをクリックします。この価格値は入力フィールドに設定されます。
このメソッドを使用すると、特に視覚的な分析からおこなうのが簡単な場合に、指値注文の価格をすばやく簡単に設定できます。より正確な方法で価格を設定する必要がある場合は、キーボードを使用して入力フィールドに価格を入力します。実装は非常に簡単です。基本クラスハンドラで、チャートをクリックするイベントを含むセクションを作成し、次のコードを追加します。
//--- The event of clicking on the chart if(id==CHARTEVENT_CLICK) { for(int i=0; i<4; i++) { if(m_pr_edit[i].GetTextBoxPointer().TextEditState()) { m_last_index=i; break; } else { if(m_last_index>=0) { //--- datetime dt =0; int window=0; //--- convert X and Y coordinates to date/time if(ChartXYToTimePrice(0,(int)lparam,(int)dparam,window,dt,m_xy_price)) { m_pr_edit[m_last_index].SetValue(DoubleToString(m_xy_price)); m_pr_edit[m_last_index].GetTextBoxPointer().Update(true); m_last_index=-1; } } } } }
ここで、編集中のフィールドを特定して覚えておき、チャートをクリックして値を受け取り、この値を入力フィールドに挿入します。主な機能と革新は、以下のビデオに示されています。
終わりに
添付されたアーカイブには、リストされたすべてのファイルが含まれています。これらのファイルは、適切なフォルダにあります。正しく動作させるためには、MQL5フォルダをターミナルフォルダに保存するだけです。MQL5フォルダのあるルートディレクトリを開くには、MetaTrader 5ターミナルでCtrl+Shift+Dキーの組み合わせを押すか、下記の図13にあるようにコンテキストメニューを使用します。
図13 MetaTrader 5ターミナルルートでMQL5フォルダを開く
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7981





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索