MQL5 クックブック: インジケーターサブウィンドウコンソールースクロールバー
Anatoli Kazharski | 24 11月, 2015
イントロダクション
様々なコントロールを試してみましょう。今回はスクロールバーを紹介します。"MQL5クックブック:インジケーターサブウィンドウコンソール - ボタン"という以前の記事のように、インジケーターサブウィンドウにて作業を進めます。OnChartEvent()関数にてイベントを扱う詳しい詳細を提供しているので、上記の記事を読んでみてください。この点はこの記事においても言及されます。 今回はMQL5リソースを用いて取得される金融商品情報の大きなリストのための垂直スクロールバーを作成します。
MQL5プログラミングに関する以前の記事にて、OBJ_LABEL (テキストラベル)グラフィカルオブジェクトをリスト作成のために使用しました。この記事では、テキストを表示するキャンバスを使用します。そのようなアプローチの利便性は、OBJ_LABELオブジェクトの代わりに- OBJ_BITMAP_LABEL (ビットマップラベル)のみを用いるためです。キャンバスにすべてのインターフェースエレメントを描画することができますが、今回はテキストのみに限ります。
そのスクロールバーはとてもシンプルです。普通矢印ボタンがありますが、この場合はありません。そんスクロールボタンはバックグラウンドとスクロールボックスのみから成り立ちます。スクロールボックスは、カーソルが図上を移動した際に色を変更します。クリックされた際、スクロールボックスが選択され、ドラッグされていることをユーザーに示すため色を変更します。スクロールオブジェクトを作成する際、OBJ_RECTANGLE_LABEL(長方形ラベル) タイプのグラフィカルオブジェクトを使用します。
インジケーター開発
プログラミングを始めましょう。前回の記事にて行われたようにインジケーターのテンプレートを作成します。まずはじめに、変数と配列を宣言しなければなりません。キャンバスを扱うことができるよう、標準ライブラリからCCanvasクラスを含みます。
#define LIST_SIZE 71 // Number of strings in the list of financial instrument properties //--- Include the class for working with the canvas #include <Canvas\Canvas.mqh> CCanvas canvas; //+------------------------------------------------------------------+ //| Global variables | //+------------------------------------------------------------------+ //--- Indicator subwindow properties int subwindow_number =WRONG_VALUE; // Subwindow number int subwindow_height =0; // Subwindow height string subwindow_shortname ="TestScrollbar"; // Short name of the indicator string prefix =subwindow_shortname+"_"; // Prefix for objects int chart_width =0; // Chart width int chart_height =0; // Chart height int chart_y_offset =0; // Distance from the chart top to the subwindow //--- Canvas properties string canvas_name =prefix+"canvas"; // Canvas name color canvas_background_color =C'20,20,20'; // Canvas background color ENUM_COLOR_FORMAT color_format =COLOR_FORMAT_XRGB_NOALPHA; // Alpha channel component is ignored //--- List properties int list_height =0; // List height int text_height =0; // Text height int font_size =15; // Font size string font_name ="Calibri"; // Font double line_size =100/LIST_SIZE; // Size of a single string on the list, expressed as percentage //--- Scrollbar properties: scroll box string scrollbar_thumb_name =prefix+"scrollbar_thumb"; // Scroll box object name int scrollbar_thumb_x1 =0; // x1 coordinate int scrollbar_thumb_y1 =0; // y1 coordinate int scrollbar_thumb_x2 =0; // x2 coordinate int scrollbar_thumb_y2 =0; // y2 coordinate double scrollbar_thumb_y_percent =0.0; // Y-coordinate expressed as percentage int scrollbar_thumb_width =9; // Width int scrollbar_thumb_height =0; // Height bool scrollbar_thumb_clicked =false; // State (whether or not the scroll box is clicked) color scrollbar_thumb_color =clrSilver; // Scroll box color color scrollbar_thumb_color_on_hover=clrDimGray; // Scroll box color when the cursor hovers over it color scrollbar_thumb_color_on_click=clrSlateGray; // Scroll box color when clicked //--- Scrollbar properties: background string scrollbar_background_name =prefix+"scrollbar_background"; // Background object name int scrollbar_background_width =9; // Background width color scrollbar_background_color =C'50,50,50'; // Background color //--- Scrollbar properties: other int scrollbar_fix_point =0; // Y-coordinate of the fix point upon clicking int scrollbar_fix_point_y_offest =0; // Distance along the Y-axis from the scrollbar top to the fix point //--- Mouse button state (pressed/released) bool mouse_button_state=false; //--- Arrays for financial instrument properties color symbol_property_colors[]; // Colors of values string symbol_property_values[]; // Values //--- Financial instrument property names string symbol_propety_names[LIST_SIZE]= { "Number of deals in the current session", "Total number of Buy orders at the moment", "Total number of Sell orders at the moment", "Volume of the last deal", "Maximum daily volume", "Minimum daily volume", "Time of the last quote", "Number of decimal places", "Spread in points", "Floating spread indication", "Maximum number of requests displayed in the Depth of Market", "Contract price calculation mode", "Order execution type", "Trading start date for an instrument (usually used for futures)", "Trading end date for an instrument (usually used for futures)", "Minimum distance in points from the current closing price for the purpose of setting Stop orders", "Freeze distance for trading operations (in points)", "Deal execution mode", "Swap calculation model", "Day of the week when triple swap is charged", "Flags of allowed order expiration modes", "Flags of allowed order filling modes", //--- "Bid - best price at which an instrument can be sold", "Maximum Bid of the day", "Minimum Bid of the day", "Ask - best price at which an instrument can be bought", "Maximum Ask of the day", "Minimum Ask of the day", "Last - last deal price", "Maximum Last of the day", "Minimum Last of the day", "Point value", "Calculated tick value for a winning position", "Calculated tick value for a losing position", "Minimum price change", "Trade contract size", "Minimum volume for deal execution", "Maximum volume for deal execution", "Minimum step of volume change for deal execution", "Maximum allowable total volume of an open position and pending orders in the same direction", "Long swap value", "Short swap value", "Initial margin - amount in the margin currency required for opening a position (1 lot)", "Maintenance margin for an instrument", "Margin requirement applicable to long positions", "Margin requirement applicable to short positions", "Margin requirement applicable to Limit orders", "Margin requirement applicable to Stop orders", "Margin requirement applicable to Stop Limit orders", "Total volume of deals in the current session", "Total turnover in the current session", "Total volume of open positions", "Total volume of buy orders at the moment", "Total volume of sell orders at the moment", "Open price of the session", "Close price of the session", "Average weighted price of the session", "Settlement price of the current session", "Minimum allowable price value for the session", "Maximum allowable price value for the session", //--- "Base currency of an instrument", "Profit currency", "Margin currency", "Current quote source", "String description of a symbol", "Name of a trading symbol in the international system of securities identification numbers (ISIN)", "Location in the symbol tree", //--- "Current number of bars for a symbol on a selected time frame", "The very first date for a symbol on a selected time frame", "The very first date in the history for a symbol on a selected time frame", "Symbol data synchronized" };
キャンバスのプロパティリストの表示に必要なすべての関数をまず書きましょう。これが終われば、スクロールバーの作成に進みます。
キャンバスを作成するために、AddCanvas()関数を記述し、CCanvasクラスのCreateBitmapLabel()メソッドの二番目のバリアントを使用します。
//+------------------------------------------------------------------+ //| Adding canvas | //+------------------------------------------------------------------+ void AddCanvas() { //--- If there is no canvas, add it if(ObjectFind(0,canvas_name)<0) canvas.CreateBitmapLabel(0,subwindow_number,canvas_name,0,0,chart_width,subwindow_height,color_format); }
インジケーターサブウィンドウのサイズに調整するため、キャンバスサイズの変更を行うメソッドが必要です。このために、CCanvasクラスのResize()関数を用いるResizeCanvas()関数を記述します。
//+------------------------------------------------------------------+ //| Resizing canvas | //+------------------------------------------------------------------+ void ResizeCanvas() { //--- If the canvas has already been added to the indicator subwindow, set the new size if(ObjectFind(0,canvas_name)==subwindow_number) canvas.Resize(chart_width,subwindow_height); //--- If there is no canvas, add it else canvas.CreateBitmapLabel(0,subwindow_number,canvas_name,0,0,chart_width,subwindow_height,color_format); }
キャンバスを削除するために、Destroy()メソッドを用います:
//+------------------------------------------------------------------+ //| Deleting canvas | //+------------------------------------------------------------------+ void DeleteCanvas() { if(ObjectFind(0,canvas_name)>0) canvas.Destroy(); }
この記事では、CCanvasクラスの他のメソッドを使用します、例えば、フォントの送信のためにFontSet() 関数や、テキストの高さを決定するTextHeight()、テキストをキャンバスに貼り付けるTextOut()、キャンバスの消去のためのErase()、再描画のための Update() などです。さらに以下にて、プログラムの中でどこで上記のメソッドが用いられているのかを見ていきます。
OnInit()関数にて初期化中に、プログラム処理の準備をしなければなりません。以下のコードは何がなされるべきかを示しています。それぞれのコメントはアクションをより理解する上で役に立ちます。CCanvasのFontSet()とTextHeight()はプログラムのこの部分でのみ用いられます。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Enable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true); //--- Set the short name IndicatorSetString(INDICATOR_SHORTNAME,subwindow_shortname); //--- Set sizes of arrays of symbol properties and their colors ArrayResize(symbol_property_colors,LIST_SIZE); ArrayResize(symbol_property_values,LIST_SIZE); //--- Set subwindow properties SetSubwindowProperties(); //--- Set the font for displaying on the canvas canvas.FontSet(font_name,font_size,FW_NORMAL); //--- Save the text size (height) for calculations text_height=canvas.TextHeight("A")-1; //--- Calculate the height of the entire list list_height=text_height*LIST_SIZE; //--- Add the canvas to the chart AddCanvas(); //--- Display the list of symbol properties ShowSymbolInfo(); //--- Refresh the chart ChartRedraw(); //--- Everything completed successfully return(INIT_SUCCEEDED); }
SetSubwindowProperties()関数は、以前のアクションから取得されています:インジケーターサブウィンドウ数とサイズをグローバル変数に割り当てます。ShowSymbolInfo()関数に進みましょう;
//+------------------------------------------------------------------+ //| Displaying current symbol information | //+------------------------------------------------------------------+ void ShowSymbolInfo(double current_thumb_position=0.0) { int list_lines =0; // Counter of strings displayed in the canvas double thumb_position =0.0; // Position of the scroll box expressed as percentage for determining the first displayed string int y_distance =0; // For determining the coordinate of the next string in the list int line_number =0; // Number of the string starting from which the list will be displayed //--- Determine the string starting from which the list will be displayed for(int i=0; i<LIST_SIZE; i++) { //--- Count strings until you reach the one starting from which the list will be displayed if(thumb_position>=current_thumb_position) break; //--- thumb_position+=line_size; line_number++; } //--- Initialize list arrays from the specified string InitializePropertyArrays(line_number); //--- Clear the canvas canvas.Erase(canvas_background_color); //--- Show the list on the canvas for(int i=line_number; i<LIST_SIZE; i++) { //--- Property name canvas.TextOut(655,y_distance,symbol_propety_names[i]+" :",ColorToARGB(clrWhite),TA_RIGHT|TA_TOP); //--- Property value canvas.TextOut(665,y_distance,symbol_property_values[i],ColorToARGB(symbol_property_colors[i]),TA_LEFT|TA_TOP); //--- Calculate the coordinate for the next string y_distance+=text_height; //--- Count the number of displayed strings list_lines++; //--- If you go beyond the subwindow boundaries, terminate the loop if(list_lines*text_height>subwindow_height) break; } //--- Refresh the canvas canvas.Update(); }
ShowSymbolInfo()関数はcurrent_thumb_positionパラメーターを持ち、標準として0になっています(標準値を使用する場合、関数に値を渡す必要があります。)このパラメーターはStringを決定し、それをもとにリストが表示されます。言い換えれば、0値はそのリストが最初から表示される必要があることを意味します。
最初の時点で、Stringの数を決定し、それに基づきリストが表示されます。値や色(上記のコードにてハイライト表示されています)の配列はInitializePropertyArrays()関数にて初期化されます。初期化は以前のループの中で決定されたStringから実行が開始されます。そのあとに、Erase()メソッドを用いて、そのキャンバスが削除されます。実際、そのキャンバスは明記された色で塗りつぶされています。最後のループにて、TextOut()メソッドを用いて、キャンバスにテキストを貼り付けます。最後に、キャンバスをUpdate()メソッドを用いて更新します。
InitializePropertyArrays()関数コードは以下にて提供されています;
//+-----------------------------------------------------------------------+ //| Initializing arrays of values and their colors for the current symbol | //+-----------------------------------------------------------------------+ void InitializePropertyArrays(int line_number) { int lines_count=0; //--- for(int i=line_number; i<LIST_SIZE; i++) { //--- Determine the value and color of the symbol property symbol_property_values[i]=GetStringSymbolInfoByIndex(i); symbol_property_colors[i]=GetColorSymbolInfoByIndex(i); //--- Increase the counter lines_count++; //--- If the number of strings exceeds the subwindow height, exit if(lines_count*text_height>subwindow_height) break; } }
上記のコードは、シンボルの属性や色の値が類似した原則を持つ二つの関数GetStringSymbolInfoByIndex()とGetColorSymbolInfoByIndex()を用いて決定されることを示します。
GetStringSymbolInfoByIndex()関数はシンプルですが、かなり多い属性のため量が膨大です。さらに、いくつかの属性を取得するために補助関数が必要です(以下のコードにてハイライト表示されています。)
//+------------------------------------------------------------------+ //| Returning the string value of the symbol property by index | //+------------------------------------------------------------------+ string GetStringSymbolInfoByIndex(int index) { string str ="-"; long l_check_value =0; double d_check_value =0.0; string s_check_value =""; //--- switch(index) { case 0 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_SESSION_DEALS); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 1 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_SESSION_BUY_ORDERS); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 2 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_SESSION_SELL_ORDERS); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 3 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_VOLUME); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 4 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_VOLUMEHIGH); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 5 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_VOLUMELOW); str=(l_check_value==0) ? "-" : IntegerToString(l_check_value); break; case 6 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_TIME); str=(l_check_value==0) ? "-" : TimeToString(l_check_value); break; case 7 : str=IntegerToString(SymbolInfoInteger(_Symbol,SYMBOL_DIGITS)); break; case 8 : str=IntegerToString(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD)); break; case 9 : str=(!SymbolInfoInteger(_Symbol,SYMBOL_SPREAD_FLOAT)) ? "false" : "true"; break; case 10 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_TICKS_BOOKDEPTH); str=(l_check_value==0) ? "-" : DoubleToString(l_check_value,_Digits); break; case 11 : str=TradeCalcModeToString(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_CALC_MODE)); break; case 12 : str=TradeModeToString(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_MODE)); break; case 13 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_START_TIME); str=(l_check_value==0) ? "-" : TimeToString(l_check_value); break; case 14 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_EXPIRATION_TIME); str=(l_check_value==0) ? "-" : TimeToString(l_check_value); break; case 15 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); str=(l_check_value==0) ? "false" : IntegerToString(l_check_value); break; case 16 : l_check_value=SymbolInfoInteger(_Symbol,SYMBOL_TRADE_FREEZE_LEVEL); str=(l_check_value==0) ? "false" : IntegerToString(l_check_value); break; case 17 : str=TradeExeModeToString(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE)); break; case 18 : str=SwapModeToString(SymbolInfoInteger(_Symbol,SYMBOL_SWAP_MODE)); break; case 19 : str=WeekdayToString(SymbolInfoInteger(_Symbol,SYMBOL_SWAP_ROLLOVER3DAYS)); break; case 20 : str=ExpirationModeToString(); break; case 21 : str=FillingModeToString(); break; //--- case 22 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_BID); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 23 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_BIDHIGH); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 24 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_BIDLOW); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 25 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_ASK); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 26 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_ASKHIGH); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 27 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_ASKLOW); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 28 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_LAST); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 29 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_LASTHIGH); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 30 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_LASTLOW); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,_Digits); break; case 31 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_POINT),_Digits); break; case 32 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE_PROFIT),2); break; case 33 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE_LOSS),2); break; case 34 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_SIZE),_Digits); break; case 35 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE),2); break; case 36 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN),2); break; case 37 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX),2); break; case 38 : str=DoubleToString(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP),2); break; case 39 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT); str=(d_check_value==0) ? "Unlimited" : DoubleToString(d_check_value,2); break; case 40 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SWAP_LONG); str=(d_check_value==0) ? "false" : DoubleToString(d_check_value,2); break; case 41 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SWAP_SHORT); str=(d_check_value==0) ? "false" : DoubleToString(d_check_value,2); break; case 42 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_INITIAL); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 43 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_MAINTENANCE); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 44 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_LONG); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 45 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_SHORT); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 46 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_LIMIT); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 47 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_STOP); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 48 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_MARGIN_STOPLIMIT); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 49 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_VOLUME); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 50 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_TURNOVER); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 51 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_INTEREST); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 52 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_BUY_ORDERS_VOLUME); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 53 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_SELL_ORDERS_VOLUME); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 54 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_OPEN); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 55 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_CLOSE); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 56 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_AW); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 57 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_PRICE_SETTLEMENT); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 58 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_PRICE_LIMIT_MIN); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; case 59 : d_check_value=SymbolInfoDouble(_Symbol,SYMBOL_SESSION_PRICE_LIMIT_MAX); str=(d_check_value==0) ? "-" : DoubleToString(d_check_value,2); break; //--- case 60 : str=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_BASE); break; case 61 : str=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_PROFIT); break; case 62 : str=SymbolInfoString(_Symbol,SYMBOL_CURRENCY_MARGIN); break; case 63 : s_check_value=SymbolInfoString(_Symbol,SYMBOL_BANK); str=(s_check_value!="") ? s_check_value : "-"; break; case 64 : str=SymbolInfoString(_Symbol,SYMBOL_DESCRIPTION); break; case 65 : s_check_value=SymbolInfoString(_Symbol,SYMBOL_ISIN); str=(s_check_value!="") ? s_check_value : "-"; break; case 66 : str=SymbolInfoString(_Symbol,SYMBOL_PATH); break; //--- case 67 : str=IntegerToString(SeriesInfoInteger(_Symbol,_Period,SERIES_BARS_COUNT)); break; case 68 : str=TimeToString((datetime)SeriesInfoInteger(_Symbol,_Period,SERIES_FIRSTDATE)); break; case 69 : str=TimeToString((datetime)SeriesInfoInteger(_Symbol,_Period,SERIES_SERVER_FIRSTDATE)); break; case 70 : str=(!(bool)SeriesInfoInteger(_Symbol,_Period,SERIES_SYNCHRONIZED)) ? "false" : "true"; break; } //--- return(str); }
上記のハイライト表示された関数: TradeCalcModeToString()、TradeModeToString()、 TradeExeModeToString()、SwapModeToString()とWeekdayToString() 単純に渡された値に応じてプロパティのStringを返します。
//+------------------------------------------------------------------+ //| Returning string representation of the margin calculation | //| method for an instrument | //+------------------------------------------------------------------+ string TradeCalcModeToString(long mode) { string str="?"; //--- switch((ENUM_SYMBOL_CALC_MODE)mode) { case SYMBOL_CALC_MODE_FOREX : str="Forex mode"; break; case SYMBOL_CALC_MODE_FUTURES : str="Futures mode"; break; case SYMBOL_CALC_MODE_CFD : str="CFD mode"; break; case SYMBOL_CALC_MODE_CFDINDEX : str="CFD index mode"; break; case SYMBOL_CALC_MODE_CFDLEVERAGE : str="CFD Leverage mode"; break; case SYMBOL_CALC_MODE_EXCH_STOCKS : str="Exchange mode"; break; case SYMBOL_CALC_MODE_EXCH_FUTURES : str="Futures mode"; break; case SYMBOL_CALC_MODE_EXCH_FUTURES_FORTS : str="FORTS Futures mode"; break; } //--- return(str); } //+------------------------------------------------------------------+ //| Returning string representation of the trade mode | //+------------------------------------------------------------------+ string TradeModeToString(long mode) { string str="-"; //--- switch((ENUM_SYMBOL_TRADE_MODE)mode) { case SYMBOL_TRADE_MODE_DISABLED : str="Trade is disabled for a given symbol"; break; case SYMBOL_TRADE_MODE_LONGONLY : str="Only long positions are allowed"; break; case SYMBOL_TRADE_MODE_SHORTONLY : str="Only short positions are allowed"; break; case SYMBOL_TRADE_MODE_CLOSEONLY : str="Only position closing operations are allowed"; break; case SYMBOL_TRADE_MODE_FULL : str="No trade restrictions"; break; } //--- return(str); } //+------------------------------------------------------------------+ //| Returning string representation of the deal execution mode | //+------------------------------------------------------------------+ string TradeExeModeToString(long mode) { string str="-"; //--- switch((ENUM_SYMBOL_TRADE_EXECUTION)mode) { case SYMBOL_TRADE_EXECUTION_REQUEST : str="Request execution"; break; case SYMBOL_TRADE_EXECUTION_INSTANT : str="Instant execution"; break; case SYMBOL_TRADE_EXECUTION_MARKET : str="Market execution"; break; case SYMBOL_TRADE_EXECUTION_EXCHANGE : str="Exchange execution"; break; } //--- return(str); } //+------------------------------------------------------------------+ //| Returning string representation of the swap calculation model | //+------------------------------------------------------------------+ string SwapModeToString(long mode) { string str="-"; //--- switch((ENUM_SYMBOL_SWAP_MODE)mode) { case SYMBOL_SWAP_MODE_DISABLED : str="No swaps"; break; case SYMBOL_SWAP_MODE_POINTS : str="Swaps calculated in points"; break; case SYMBOL_SWAP_MODE_CURRENCY_SYMBOL : str="Swaps calculated in base currency of the symbol"; break; case SYMBOL_SWAP_MODE_CURRENCY_MARGIN : str="Swaps calculated in margin currency of the symbol"; break; case SYMBOL_SWAP_MODE_CURRENCY_DEPOSIT : str="Swaps calculated in the client's deposit currency"; break; case SYMBOL_SWAP_MODE_INTEREST_CURRENT : str="Swaps expressed as a percent per annum of the instrument price"; break; case SYMBOL_SWAP_MODE_INTEREST_OPEN : str="Swaps expressed as a percent per annum of the position opening price"; break; case SYMBOL_SWAP_MODE_REOPEN_CURRENT : str="Swaps based on position reopening (close price +/-)"; break; case SYMBOL_SWAP_MODE_REOPEN_BID : str="Swaps based on position reopening (bid price +/-)"; break; } //--- return(str); } //+------------------------------------------------------------------+ //| Returning string representation of the day of the week | //+------------------------------------------------------------------+ string WeekdayToString(long day) { string str="-"; //--- switch((ENUM_DAY_OF_WEEK)day) { case SUNDAY : str="Sunday"; break; case MONDAY : str="Monday"; break; case TUESDAY : str="Tuesday"; break; case WEDNESDAY : str="Wednesday"; break; case THURSDAY : str="Thursday"; break; case FRIDAY : str="Friday"; break; case SATURDAY : str="Saturday"; break; } //--- return(str); }
GetStringExpirationMode()とGetStringFillingMode()関数では、現在のシンボルにて使用できる記述モードや注文の期限に依存してStringの表現が生成されます。
//+------------------------------------------------------------------+ //| Returning string representation of the order expiration modes | //+------------------------------------------------------------------+ string ExpirationModeToString() { string str=""; // For string generation //--- Variables for checking the modes bool gtc =false; // The order is valid for an unlimited time until explicitly canceled bool day =false; // The order is valid until the end of the day bool specified =false; // The expiration time is specified in the order bool specified_day =false; // The expiration date is specified in the order //--- Check the modes gtc =IsExpirationTypeAllowed(_Symbol,SYMBOL_EXPIRATION_GTC); day =IsExpirationTypeAllowed(_Symbol,SYMBOL_EXPIRATION_DAY); specified =IsExpirationTypeAllowed(_Symbol,SYMBOL_EXPIRATION_SPECIFIED); specified_day =IsExpirationTypeAllowed(_Symbol,SYMBOL_EXPIRATION_SPECIFIED_DAY); //--- Generate a string of the modes available if(gtc) { StringAdd(str,"GTC"); if(day || specified || specified_day) StringAdd(str," / "); } //--- if(day) { StringAdd(str,"Day"); if(specified || specified_day) StringAdd(str," / "); } //--- if(specified) { StringAdd(str,"Specified"); if(specified_day) StringAdd(str," / "); } //--- if(specified_day) StringAdd(str,"Specified Day"); //--- return(str); } //+------------------------------------------------------------------+ //| Returning string representation of the volume filling modes | //+------------------------------------------------------------------+ string FillingModeToString() { //--- Variable for string generation string str=""; //--- Variables for checking the modes: // "Fill or Kill" - if the required order volume cannot be filled at the specified price, // the order is canceled and the deal is not executed bool fok=false; // "Immediate or Cancel" - if the deal volume can only be partially filled at the price specified in the order, // the deal is executed to the extent of the volume available. The remaining volume of the order is canceled // and the new order is not placed bool ioc=false; // "Return" - The deal is executed to the extent of the volume available at the price specified in the order. // A new order is placed for the remaining volume at the same price bool return_remainder=false; //--- Check the modes fok =IsFillingTypeAllowed(_Symbol,SYMBOL_FILLING_FOK); ioc =IsFillingTypeAllowed(_Symbol,SYMBOL_FILLING_IOC); //--- For "Market execution" and "Exchange execution" modes ENUM_SYMBOL_TRADE_EXECUTION symbol_trade_exemode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); return_remainder=(symbol_trade_exemode==SYMBOL_TRADE_EXECUTION_MARKET || symbol_trade_exemode==SYMBOL_TRADE_EXECUTION_EXCHANGE) ? true : false; //--- Generate a string of the modes available if(fok) { StringAdd(str,"Fill or Kill"); if(ioc || return_remainder) StringAdd(str," / "); } //--- if(ioc) { StringAdd(str,"Immediate or Cancel"); if(return_remainder) StringAdd(str," / "); } //--- if(return_remainder) StringAdd(str,"Return"); //--- return(str); }
それぞれのモードが使用できるか個別にチェックされる必要があるため、ドキュメントの例として提供されている補助関数IsExpirationTypeAllowed()と IsFillingTypeAllowed()を使用します。
//+------------------------------------------------------------------+ //| Checking if a given expiration mode is allowed | //+------------------------------------------------------------------+ bool IsExpirationTypeAllowed(string symbol, int exp_type) { //--- Get the value of the property describing the allowable expiration modes int expiration=(int)SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_MODE); //--- Return true if the exp_type mode is allowed return((expiration&exp_type)==exp_type); } //+------------------------------------------------------------------+ //| Checking if a given filling mode is allowed | //+------------------------------------------------------------------+ bool IsFillingTypeAllowed(string symbol, int fill_type) { //--- Get the value of the property describing the filling mode int filling=(int)SymbolInfoInteger(symbol,SYMBOL_FILLING_MODE); //--- Return true if the fill_type mode is allowed return((filling&fill_type)==fill_type); }
シンボルの属性のString値をチェックしました。それでは、GetColorSymbolInfoByIndex()関数を見てみましょう。この関数のコードは、すべてのプロパティが表示されている値に依存しているわけではないため、とてもシンプルです。
//+------------------------------------------------------------------+ //| Returning the symbol property color by index | //+------------------------------------------------------------------+ color GetColorSymbolInfoByIndex(int index) { double check_value =0.0; color clr =clrWhiteSmoke; //--- switch(index) { case 6 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_TIME)>0) ? clrCornflowerBlue : clrWhiteSmoke; break; //--- case 9 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_SPREAD_FLOAT)>0) ? clrGold : clrRed; break; //--- case 13 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_START_TIME)>0) ? clrCornflowerBlue : clrWhiteSmoke; break; case 14 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_EXPIRATION_TIME)>0) ? clrCornflowerBlue : clrWhiteSmoke; break; //--- case 15 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL)>0) ? clrWhiteSmoke : clrRed; break; case 16 : clr=(SymbolInfoInteger(_Symbol,SYMBOL_TRADE_FREEZE_LEVEL)>0) ? clrWhiteSmoke : clrRed; break; //--- case 20 : clr=clrGold; break; case 21 : clr=clrGold; break; //--- case 39 : clr=(SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT)>0) ? clrWhiteSmoke : clrGold; break; case 40 : clr=(SymbolInfoDouble(_Symbol,SYMBOL_SWAP_LONG)>0) ? clrLime : clrRed; break; case 41 : clr=(SymbolInfoDouble(_Symbol,SYMBOL_SWAP_SHORT)>0) ? clrLime : clrRed; break; //--- case 60 : clr=clrGold; break; case 61 : clr=clrGold; break; case 62 : clr=clrGold; break; //--- case 68 : clr=(SeriesInfoInteger(_Symbol,_Period,SERIES_FIRSTDATE)>0) ? clrCornflowerBlue : clrWhiteSmoke; break; case 69 : clr=(SeriesInfoInteger(_Symbol,_Period,SERIES_SERVER_FIRSTDATE)>0) ? clrCornflowerBlue : clrWhiteSmoke; break; case 70 : clr=(!(bool)SeriesInfoInteger(_Symbol,_Period,SERIES_SYNCHRONIZED)) ? clrRed : clrGold; break; } //--- return(clr); }
インジケーターをコンパイルし、チャートに加えると、以下のスクリーンショットでご覧のようにサブウィンドウにてシンボルのプロパティリストを見ることができます。
図1. スクロールバーのないチャートに貼り付けられたインジケーター
これすべてが一つのオブジェクトです!
さらに、垂直スクロールバーを扱う関数を記述します。この記事の冒頭にてすでに紹介されている通り、スクロールバーは二つのグラフィカルオブジェクトOBJ_RECTANGLE_LABEL (長方形ラベル)を用いて作成されます。一つは背景として使用され、一方はスクロールボックスになります。そのスクロールバーは、インジケーターサブウィンドウの右に位置しています。
CreateRectangleLable() - 長方形ラベルを作成する関数
//+------------------------------------------------------------------+ //| Creating a rectangle | //+------------------------------------------------------------------+ void CreateRectangleLable(long chart_id, // chart id int sub_window, // window number string object_name, // object name int x_distance, // X-coordinate int y_distance, // Y-coordinate int x_size, // width int y_size, // height ENUM_BASE_CORNER corner, // chart corner color border_color, // border color color background_color, // background color bool selectable, // cannot select the object if FALSE bool is_on_background) // background position { //--- If the object has been created successfully if(ObjectCreate(chart_id,object_name,OBJ_RECTANGLE_LABEL,sub_window,0,0)) { // set its properties ObjectSetInteger(chart_id,object_name,OBJPROP_XDISTANCE,x_distance); ObjectSetInteger(chart_id,object_name,OBJPROP_YDISTANCE,y_distance); ObjectSetInteger(chart_id,object_name,OBJPROP_XSIZE,x_size); ObjectSetInteger(chart_id,object_name,OBJPROP_YSIZE,y_size); ObjectSetInteger(chart_id,object_name,OBJPROP_BORDER_TYPE,BORDER_FLAT); // set the flat border style ObjectSetInteger(chart_id,object_name,OBJPROP_COLOR,border_color); ObjectSetInteger(chart_id,object_name,OBJPROP_CORNER,corner); ObjectSetInteger(chart_id,object_name,OBJPROP_BGCOLOR,background_color); ObjectSetInteger(chart_id,object_name,OBJPROP_SELECTABLE,selectable); ObjectSetInteger(chart_id,object_name,OBJPROP_BACK,is_on_background); // it will be used as a background if true ObjectSetString(chart_id,object_name,OBJPROP_TOOLTIP,"\n"); // no tooltip if "\n" } }
スクロールボックスやスクロールバー背景サイズを作成し、修正する関数を記述しましょう: AdjustScrollbarThumb()・ AdjustScrollbarBackground():
//+------------------------------------------------------------------+ //| Adding scroll box or adjusting its size | //+------------------------------------------------------------------+ void AdjustScrollbarThumb() { //--- Calculate the scroll box size relative to the subwindow height CalculateScrollbarThumbHeight(); //--- If the scroll box is already available in the chart, adjust its properties if(ObjectFind(0,scrollbar_thumb_name)>0) { //--- Set the height and X-coordinate ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_YSIZE,scrollbar_thumb_height); ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_XDISTANCE,chart_width-scrollbar_thumb_width); //--- Adjust the scroll box position along the Y-axis if you go below the subwindow bottom boundary if(scrollbar_thumb_y1+scrollbar_thumb_height>subwindow_height) ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_YDISTANCE,subwindow_height-scrollbar_thumb_height); } //--- Create the scroll box if it does not exist else { CreateRectangleLable(0,subwindow_number,scrollbar_thumb_name, chart_width-scrollbar_thumb_width,0,scrollbar_thumb_width,scrollbar_thumb_height, CORNER_LEFT_UPPER,clrSilver,clrSilver,false,false); } } //+------------------------------------------------------------------+ //| Adding the scrollbar background or adjusting its size | //+------------------------------------------------------------------+ void AdjustScrollbarBackground() { //--- If the scrollbar background is already available in the chart, adjust its properties if(ObjectFind(0,scrollbar_background_name)>0) { //--- Set the background size ObjectSetInteger(0,scrollbar_background_name,OBJPROP_YDISTANCE,0); ObjectSetInteger(0,scrollbar_background_name,OBJPROP_XDISTANCE,chart_width-scrollbar_background_width); ObjectSetInteger(0,scrollbar_background_name,OBJPROP_YSIZE,subwindow_height); } //--- If there is no background, create it else { CreateRectangleLable(0,subwindow_number,scrollbar_background_name, chart_width-scrollbar_background_width,0,scrollbar_background_width,subwindow_height, CORNER_LEFT_UPPER,scrollbar_background_color,scrollbar_background_color,false,false); } }
スクロールボックスの高さはAdjustScrollbarThumb()関数の最初に計算されます。
//+------------------------------------------------------------------+ //| Calculating the scroll box size relative to the subwindow height | //+------------------------------------------------------------------+ void CalculateScrollbarThumbHeight() { //--- If the subwindow height is greater than the list size, save the subwindow size if(subwindow_height>=list_height) scrollbar_thumb_height=subwindow_height-1; //--- Otherwise calculate the scroll box size else { double height_temp=0.0; //--- Calculate the scroll box size relative to the subwindow height height_temp=subwindow_height-(((double)subwindow_height/100)*(100-((double)subwindow_height/list_height)*100)); //--- Set the minimum size at 25% of the subwindow height if(height_temp/subwindow_height<0.25) height_temp=subwindow_height/4; //--- Save to the global variable scrollbar_thumb_height=(int)height_temp; } }
グラフィカルオブジェクトを削除し忘れないようにしてください:
//+------------------------------------------------------------------+ //| Deleting the scrollbar | //+------------------------------------------------------------------+ void DeleteScrollbar() { DeleteObjectByName(scrollbar_thumb_name); DeleteObjectByName(scrollbar_background_name); } //+------------------------------------------------------------------+ //| Deleting the object by name | //+------------------------------------------------------------------+ void DeleteObjectByName(string object_name) { //--- If such object exists if(ObjectFind(0,object_name)>=0) { //--- If an error occurred when deleting, print the relevant message if(!ObjectDelete(0,object_name)) Print("Error ("+IntegerToString(GetLastError())+") when deleting the object!"); } }
最も面白い部分に移りましょう;スクロールボックスのドラッグ、リストの移動を引き起こす関数を記述します。カーソルが頭上にある際や、スクロールボックスがコントールがスクロールボックスに渡され、スクロールボックスがドラッグされるようスクロールボックスがクリックされた時などに色を変更する機能を実装する必要があります。このため、スクロールボックスの色は追加でクリックすると変更されます。
スクロールボックスはかなり幅が狭いため、移動すると、カーソルの横への移動を体験するでしょう。この問題を修復するため、コントロールをスクロールボックスに渡し、その間、マウス左ボタンを押します。
以下は上記で紹介した関数のコードです。
//+------------------------------------------------------------------+ //| Setting the scroll box color | //+------------------------------------------------------------------+ void SetScrollbarThumbColor(color thumb_color) { ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_COLOR,thumb_color); ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_BGCOLOR,thumb_color); } //+------------------------------------------------------------------+ //| Setting the scroll box boundaries | //+------------------------------------------------------------------+ void SetScrollbarThumbBoundaries() { scrollbar_thumb_x1=(int)ObjectGetInteger(0,scrollbar_thumb_name,OBJPROP_XDISTANCE); scrollbar_thumb_y1=(int)ObjectGetInteger(0,scrollbar_thumb_name,OBJPROP_YDISTANCE); scrollbar_thumb_x2=scrollbar_thumb_x1+scrollbar_thumb_width; scrollbar_thumb_y2=scrollbar_thumb_y1+scrollbar_thumb_height; } //+------------------------------------------------------------------+ //| Changing the color of the scroll box when the cursor hovers over | //+------------------------------------------------------------------+ void ChangeScrollbarThumbColorOnHover(int x,int y) { //--- If the cursor is within the scroll box area, make the color darker if(x>scrollbar_thumb_x1 && x<scrollbar_thumb_x2 && y>scrollbar_thumb_y1 && y<scrollbar_thumb_x2) SetScrollbarThumbColor(scrollbar_thumb_color_on_hover); //--- If the cursor is outside the scroll box boundaries else { //--- If the mouse button is released, set the standard scroll box color if(!mouse_button_state) SetScrollbarThumbColor(scrollbar_thumb_color); } } //+------------------------------------------------------------------+ //| Determining the scroll box state | //+------------------------------------------------------------------+ void SetScrollbarThumbState(int x,int y) { //--- If the mouse cursor is within the scroll box boundaries if(x>scrollbar_thumb_x1 && x<scrollbar_thumb_x2 && y>scrollbar_thumb_y1 && y<scrollbar_thumb_x2) { //--- If the mouse button is pressed, save it if(mouse_button_state) scrollbar_thumb_clicked=true; } //--- If the cursor is outside the scroll box boundaries else { //--- If the mouse button is released, disable the scroll box control if(!mouse_button_state) ZeroScrollbarThumbVariables(); } } //+------------------------------------------------------------------+ //| Zeroing out variables related to scroll box movement | //+------------------------------------------------------------------+ void ZeroScrollbarThumbVariables() { scrollbar_thumb_clicked =false; scrollbar_fix_point =0; scrollbar_fix_point_y_offest =0; }
これらはスクロールボックスを移動させるために必要な全ての関数ではありません。実際、スクロールボックスの移動がイベントに基づいています。言い換えれば、もしチャート上にてマウスボタンが押された場合、特定のアクションが引き起こされます。そして、マウスボタン押しっぱなしで明記されたピクセル数分カーソルが移動します。この場合、スクロールボックスの位置の変化になり、結果的にシンボルの属性リストになります。とてもシンプルです。
以下にて、上記のアクションを実装する上で必要なMoveThumb()、UpdateListAndScrollbarThumb()、ThumbYCoordinateToPercent() 関数をご覧になれます。
//+------------------------------------------------------------------+ //| Moving the scroll box vertically to the specified coordinate | //+------------------------------------------------------------------+ void MoveThumb(int y) { int threshold =1; // Threshold in pixels for recalculation int new_y_point =0; // New Y-coordinate //--- If the mouse button is pressed if(mouse_button_state) { //--- Set the clicked scroll box color SetScrollbarThumbColor(scrollbar_thumb_color_on_click); //--- Save the current Y-coordinate of the cursor if(scrollbar_fix_point==0) scrollbar_fix_point=y; //--- Save the distance from the scroll box top to the cursor if(scrollbar_fix_point_y_offest==0) scrollbar_fix_point_y_offest=scrollbar_thumb_y1-scrollbar_fix_point; } //--- If you scrolled down below the threshold value, while keeping the button pressed if(y-scrollbar_fix_point>=threshold) { //--- If you are still within the subwindow boundaries if(scrollbar_thumb_y1+scrollbar_thumb_height+threshold<subwindow_height) new_y_point=y+scrollbar_fix_point_y_offest; else { scrollbar_fix_point_y_offest=0; new_y_point=int(subwindow_height-scrollbar_thumb_height)-1; } //--- Refresh the list and the scroll box UpdateListAndScrollbarThumb(new_y_point); return; } //--- If you scrolled up above the threshold value, while keeping the button pressed if(y-scrollbar_fix_point<=-(threshold)) { //--- If you are still within the subwindow boundaries if(y-fabs(scrollbar_fix_point_y_offest)>=0) new_y_point=y-fabs(scrollbar_fix_point_y_offest); else { new_y_point=0; scrollbar_fix_point_y_offest=0; } //--- Refresh the list and the scroll box UpdateListAndScrollbarThumb(new_y_point); return; } } //+------------------------------------------------------------------+ //| Refreshing the list and the scroll box position | //+------------------------------------------------------------------+ void UpdateListAndScrollbarThumb(int new_point) { //--- Set the new Y-coordinate for the scroll box ObjectSetInteger(0,scrollbar_thumb_name,OBJPROP_YDISTANCE,new_point); //--- Refresh the list of the symbol properties relative to the current scroll box position ShowSymbolInfo(ThumbYCoordinateToPercent(new_point)); //--- Zero out the fix point scrollbar_fix_point=0; } //+------------------------------------------------------------------+ //| Converting the Y-coordinate of the scroll box to percentage | //+------------------------------------------------------------------+ double ThumbYCoordinateToPercent(long y) { if(subwindow_height<=0) subwindow_height=1; //--- return(((double)y/subwindow_height)*100); }
全ての関数は特定の順序で配置され、プログラムが初期設定通り動くようにする必要があります。OnChartEvent() 関数にて、ユーザーがインジケーターサブウィンドウや、サブウィンドウにあるスクロールバーやリストを扱う手助けをするイベントのハンドリングを行う必要があります。
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Track mouse clicks on the chart if(id==CHARTEVENT_CLICK) { //--- Zero out variables related to the scroll box movement ZeroScrollbarThumbVariables(); //--- Refresh the chart ChartRedraw(); return; } //--- Track the cursor movement and the state of the left mouse button if(id==CHARTEVENT_MOUSE_MOVE) { int x =(int)lparam; // X-coordinate int y =(int)dparam; // Y-coordinate int window =WRONG_VALUE; // Number of the window where the cursor is located datetime time =NULL; // Time corresponding to the X-coordinate double price =0.0; // Price corresponding to the Y-coordinate //--- Set subwindow properties SetSubwindowProperties(); //--- Check and save the state of the mouse button CheckMouseButtonState(sparam); //--- Get the position of the cursor if(ChartXYToTimePrice(0,x,y,window,time,price)) { //--- If the cursor is within the subwindow boundaries if(window==subwindow_number) { //--- Disable scrolling of the price chart ChartSetInteger(0,CHART_MOUSE_SCROLL,false); //--- Recalculate the Y coordinate relative to the indicator subwindow ChartYToSubwindowY(y); //--- Determine the scroll box boundaries SetScrollbarThumbBoundaries(); //--- Change the scroll box color when the cursor moves over it ChangeScrollbarThumbColorOnHover(x,y); //--- Determine the scroll box state SetScrollbarThumbState(x,y); //--- If the control is passed to the scroll box, drag it and refresh the list if(scrollbar_thumb_clicked) MoveThumb(y); } //--- If the cursor is outside the subwindow boundaries else { //--- Enable scrolling of the price chart ChartSetInteger(0,CHART_MOUSE_SCROLL,true); //--- If the mouse button is released, set the standard scroll box color if(!scrollbar_thumb_clicked) SetScrollbarThumbColor(scrollbar_thumb_color); } } //--- If the position of the cursor could not be determined else { //--- If the control has not been passed to the scroll box, set the standard scroll box color if(!scrollbar_thumb_clicked) SetScrollbarThumbColor(scrollbar_thumb_color); } //--- Refresh the chart ChartRedraw(); return; } //--- Track the change of properties and size of the chart if(id==CHARTEVENT_CHART_CHANGE) { //--- Set subwindow properties SetSubwindowProperties(); //--- Get the Y-coordinate of the scroll box scrollbar_thumb_y1=(int)ObjectGetInteger(0,scrollbar_thumb_name,OBJPROP_YDISTANCE); //--- If the subwindow size is zero, exit if(subwindow_height<=0) return; //--- Set the new canvas size ResizeCanvas(); //--- Refresh the scrollbar background AdjustScrollbarBackground(); //--- Refresh the scroll box AdjustScrollbarThumb(); //--- Refresh the data on the canvas ShowSymbolInfo(ThumbYCoordinateToPercent(scrollbar_thumb_y1)); //--- return; } }
上記のコードにてハイライト表示されている関数は補助関数です。記述されてるコメントからその目的を理解できます。
//+-------------------------------------------------------------------+ //| Checking the mouse button state | //+-------------------------------------------------------------------+ void CheckMouseButtonState(string state) { //--- Left mouse button is pressed if(state=="1") mouse_button_state=true; //--- Left mouse button is released if(state=="0") { //--- Zero out variables ZeroScrollbarThumbVariables(); mouse_button_state=false; } } //+-------------------------------------------------------------------+ //| Recalculating the Y-coordinate relative to the indicator subwindow| //+-------------------------------------------------------------------+ void ChartYToSubwindowY(int &y) { //--- Get the distance from the chart top to the indicator subwindow chart_y_offset=(int)ChartGetInteger(0,CHART_WINDOW_YDISTANCE,subwindow_number); //--- Recalculate the Y-coordinate relative to the indicator subwindow y-=chart_y_offset; }
キャンバスと同様に、スクロールバーは初期化中インジケーターサブウィンドウに追加される必要があります。
//+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Enable tracking of mouse events ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true); //--- Set the short name IndicatorSetString(INDICATOR_SHORTNAME,subwindow_shortname); //--- Set sizes of arrays of symbol properties and their colors ArrayResize(symbol_property_colors,LIST_SIZE); ArrayResize(symbol_property_values,LIST_SIZE); //--- Set subwindow properties SetSubwindowProperties(); //--- Set the font for displaying on the canvas canvas.FontSet(font_name,font_size,FW_NORMAL); //--- Save the text size (height) for calculations text_height=canvas.TextHeight("A")-1; //--- Calculate the height of the entire list list_height=text_height*LIST_SIZE; //--- Add the canvas to the chart AddCanvas(); //--- Add the scrollbar: background and scroll box AdjustScrollbarBackground(); AdjustScrollbarThumb(); //--- Display the list of symbol properties ShowSymbolInfo(); //--- Refresh the chart ChartRedraw(); //--- Everything completed successfully return(INIT_SUCCEEDED); }
OnDeinit()関数にて「きれいにする」のを忘れないでください。ディイニシャライゼーションの理由に応じて、プログラムはより正確にセットアップされます。
//+------------------------------------------------------------------+ //| Deinitialization | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { if(reason==REASON_REMOVE || // If the indicator has been removed from the chart or reason==REASON_CHARTCHANGE || // the symbol or time frame has been modified or reason==REASON_RECOMPILE || // the program has been recompiled or reason==REASON_CHARTCLOSE || // the chart has been closed or reason==REASON_CLOSE) // the terminal has been closed { //--- Delete the scrollbar DeleteScrollbar(); //--- Delete the canvas DeleteCanvas(); //--- Enable scrolling of the price chart ChartSetInteger(0,CHART_MOUSE_SCROLL,true); //--- Disable cursor tracking ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,false); //--- Refresh the chart ChartRedraw(); } }
最後に、リアルタイムモードにて幾つかのシンボルの属性がリフレッシュされるよう、いくつかのコードをOnCalculate()関数に追加する必要があります;
すべてが完了しました。ソースコードはこの記事に添付されており、ダウンロードすることができます。この記事で扱われている関数のオペレーションは以下のビデオでもご覧になれます。
結論
スクロールバーコントロールを確認し終えました。この記事は、スクロールバーがキャンバスに位置する個別のグラフィカルオブジェクトにていかに作成されるかを示しました。今後の記事にて、クラスのメソッドを用いて、全ての機能を実装していきたいです。