MQL5の構造体とデータ表示メソッド
内容
- はじめに
- MqlDateTime構造体
- MqlDateTime, 表示メソッド
- MqlDateTime構造体データを操作するための関数
- 補助関数
- MqlDateTime構造体の年
- MqlDateTime構造体の月
- MqlDateTime構造体の日
- MqlDateTime構造体の時間
- MqlDateTime構造体の分
- MqlDateTime構造体の秒数
- MqlDateTime構造体の曜日
- MqlDateTime構造体の1年の日数
- 使用例
- MqlTick構造体
- MqlTick、表示メソッド
- MqlTick構造体データを操作するための関数
- 補助関数
- MqlTick構造体の時間
- MqlTick構造体の買値
- MqlTick構造体の売値
- MqlTick構造体の最終取引価格
- MqlTick構造体の最終価格ボリューム
- MqlTick構造体のミリ秒単位の時間
- MqlTick構造体のティックフラグ
- MqlTick構造体で精度を高めた最終価格ボリューム
- 使用例
- MqlRates構造体
- MqlBookInfo構造体
- MqlBookInfo、表示メソッド
- MqlBookInfo構造体データを操作するための関数
- MqlBookInfo市場深度構造体の注文タイプ
- MqlBookInfo市場深度構造体の注文価格
- MqlBookInfo市場深度構造体の注文量
- 精度を高めたボリューム
- 使用例
- 結論
はじめに
構造体は、単一の変数から任意の定義に属する論理的に関連するデータを格納、記録、検索するための便利なツールです。
MQL5には、サービス情報の保存と送信を目的とした12の定義済み構造体があります。
- MqlDateTimeは日付と時刻を表すためのものです。
- MqlParamは、IndicatorCreate()関数を使用して指標ハンドルを作成する際に入力を渡すことができます。
- MqlRatesは、価格、出来高、スプレッドを含む過去のデータの情報を提供します。
- MqlBookInfoは、板情報(相場ウィンドウ)に表示されるデータを取得します。
- MqlTradeRequestは、取引操作をおこなう際に取引リクエストを作成するためのものです。
- MqlTradeCheckResultは、準備された取引リクエストを送信する前に確認することができます;
- MqlTradeResultには、OrderSend()関数によって送信された取引リクエストに対する取引サーバーの応答が含まれます。
- MqlTradeTransactionには取引の説明が含まれています。
- MqlTickは、現在の価格に関する最も必要なデータをタイムリーに取得するために設計されています。
- 経済指標カレンダーの構造体は、リアルタイムでMetaTrader 5プラットフォームに送信される経済指標カレンダーイベントのデータを取得するために使用されます。経済カレンダーの関数により、新しいレポートが発表された直後にマクロ経済パラメータを分析することができます。関連する値が遅延なくソースから直接ブロードキャストされるためです。
MqlParamおよびMqlTradeRequest構造体は、指標を作成し、取引リクエストをサーバーに送信するための技術情報を送信します。完成した構造体のデータ送信結果に応じて、構造体の必要項目を埋めていきます。言い換えれば、これらの構造体では、プログラマーがこれらの構造体のフィールドに記入したデータを表示する必要は特にありません。
しかし、残りの構造体はクエリ結果を返し、各フィールドはターミナルサブシステムか取引サーバーによって埋められます。このような構造体からデータを取得したり、プログラムによって構造体のフィールドに入力されたデータを分析したり、あるいはログに出力して手動で分析したりすることは、プログラム上の意思決定や、論理エラーの発生箇所を把握発見するために非常に便利で必要なことです。
構造体のすべてのフィールドを表示するためには、標準的なArrayPrint()関数があります。この関数では、配列に含まれるデータを便利な表形式で、扱われる構造体の型とともに表示します。しかし、表形式で表現するよりも便利なために、構造体から別の形式でデータを表示する必要があることもあります。たとえば、構造体のすべてのフィールドを、ヘッダーと対応するデータとともに1行で表示する必要があるかもしれません。大量のデータを分析するには、こちらの方が便利かもしれません。同時に、構造体フィールドの説明や対応するデータの別の表現など、より詳細なビューが必要な場合もあります。
今回の記事では、構造体データを見るための標準的なツールを見て、操作ログで構造体データをさまざまに表示するためのカスタム関数を作成します。
MqlDateTime構造体
このデータ構造体には、int型のフィールドが8つ含まれています。
struct MqlDateTime { int year; // year int mon; // month int day; // day int hour; // hour int min; // minutes int sec; // seconds int day_of_week; // day of the week (0-Sunday, 1-Monday, ... ,6-Saturday) int day_of_year; // number of a day in the year (1st of January has number 0) };
構造体フィールドを埋めるためには、標準関数TimeCurrent()、TimeGMT()、TimeLocal()、TimeTradeServer()、TimeToStruct()が使用されます。
最初の4つの関数は、現在の日付、GMT日付、ローカルコンピュータの時刻、取引サーバーの日付を返すだけでなく、それぞれ1つのオーバーロードを持っています。関数の仮パラメータでは、参照によって日付構造体を渡すことができます。関数実行後、関数に渡された構造体フィールドは、関数が返した日付データで埋められます。
TimeToStruct()関数は、特にdatetime 値型(1970年01月01日からの秒数)からMqlDateTime構造体型変数に構造体を埋めるように設計されています。
bool TimeToStruct( datetime dt, // date and time MqlDateTime& dt_struct // structure for accepting values );
成功すればtrue、そうでなければfalseが返されます。この操作の後、日付構造体は、最初のdatetime型の変数パラメータで渡された時間データで満たされます。
日付の構造体は完成しましたが、どうやって表示するのでしょうか。標準のTimeToString()関数は、1970年1月1日からの秒単位の時刻を含む値を「yyyy.mm.dd hh:min:sec」形式の文字列に変換します。
ただし、この関数はMqlDateTime構造体では動作せず、datetime日付で動作します。では、この構造体を時間の値に戻すべきでしょうか。もちろん、そんなことはありません。各関数は、それぞれの目的に応じたものです。年、月、時間、分、曜日など、日付構造体から日付と時刻の構成要素を個別に取り出すことができますが、すべての構造体データを表示するにはどうすればいいのでしょうか。
ArrayPrint()関数は、単純な型または単純な構造体の配列をログに記録するもので、このタスクに適しています。表の形でデータを表示し、列は構造体のフィールド、行は配列のセルを表します。言い換えれば、1つの日付構造体を表示するには、1の配列が必要です。D1チャートからデータを取得する場合、1取引週の配列サイズは通常5取引日となります。
MqlDateTime, 表示メソッド
次の関数は、ArrayPrint()を使用して、操作ログの現在時刻から取得した日付構造体を表示します。
void OnStart() { //--- Declare a date structure variable MqlDateTime time; //--- Get the current time and at the same time fill in the date structure TimeCurrent(time); //--- Declare an array with the MqlDateTime type and write the data of the filled structure into it MqlDateTime array[1]; array[0]=time; //--- Display the header and time using the standard ArrayPrint() Print("Time current (ArrayPrint):"); ArrayPrint(array); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
それぞれ、日付構造体を受け取り、それを操作ログに表示する関数は次のようになります。
//+------------------------------------------------------------------+ //| Take a date structure and display its data to the journal. | //| Use ArrayPrint() for display | //+------------------------------------------------------------------+ void MqlDateTimePrint(const MqlDateTime& time_struct) { //--- Declare an array with the MqlDateTime type and write the data of the obtained structure into it MqlDateTime array[1]; array[0]=time_struct; //--- Print the array ArrayPrint(array); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
この関数は、time_struct変数に渡された日付を操作ログに表示することができます。
以下は、上で紹介した関数を使用して、1つの日付構造体をログ記録する関数です。
void OnStart() { //--- Declare a date structure variable MqlDateTime time; //--- Get the current time and at the same time fill in the date structure TimeCurrent(time); //--- Display the header and time using the standard ArrayPrint() Print("Time current (ArrayPrint):"); MqlDateTimePrint(time); /* Sample output: Time current (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 12 8 37 1 197 */ }
日付の配列を表示する必要がある場合(結局のところ、これがArrayPrint()の主な目的です)、データ配列をdatetime関数に渡し、MqlDateTime配列を埋めて表示する必要があります。
以下は、datetime配列を受け取り、MqlDateTime配列を表示する関数です。
//+------------------------------------------------------------------+ //| Accept the datetime array, convert it into MqlDateTime and | //| display converted data into the journal. | //| Use ArrayPrint() for display | //+------------------------------------------------------------------+ void MqlDateTimePrint(const datetime& array_time[]) { //--- Declare a dynamic array of the MqlDateTime type MqlDateTime array_struct[]; //--- Get the size of the array passed to the function int total=(int)array_time.Size(); //--- If an empty array is passed, report on that and leave the function if(total==0) { PrintFormat("%s: Error. Empty array.",__FUNCTION__); return; } //--- Change the size of the MqlDateTime array to match the size of the datetime array ResetLastError(); if(ArrayResize(array_struct,total)!=total) { PrintFormat("%s: ArrayResize() failed. Error %s",__FUNCTION__,(string)GetLastError()); return; } //--- Convert dates from the datetime array into the date structure in the MqlDateTime array for(int i=0;i<total;i++) { ResetLastError(); if(!TimeToStruct(array_time[i],array_struct[i])) PrintFormat("%s: [%s] TimeToStruct() failed. Error %s",__FUNCTION__,(string)i,(string)GetLastError()); } //--- Print the filled MqlDateTime array ArrayPrint(array_struct); /* Sample output: Time data of the last 10 bars GBPUSD H1 (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 7 0 0 1 197 [1] 2023 7 17 8 0 0 1 197 [2] 2023 7 17 9 0 0 1 197 [3] 2023 7 17 10 0 0 1 197 [4] 2023 7 17 11 0 0 1 197 [5] 2023 7 17 12 0 0 1 197 [6] 2023 7 17 13 0 0 1 197 [7] 2023 7 17 14 0 0 1 197 [8] 2023 7 17 15 0 0 1 197 [9] 2023 7 17 16 0 0 1 197 */ }
したがって、上記の関数を使用して操作ログにdatetime配列を出力する関数は次のようになります。
void OnStart() { //--- Declare a time array datetime array[]; //--- Copy the time of the last 10 bars to the array ResetLastError(); if(CopyTime(Symbol(),Period(),0,10,array)<0) { PrintFormat("CopyTime() failed. Error %s",(string)GetLastError()); return; } //--- Display the header and the time data array of the last 10 bars using the standard ArrayPrint() PrintFormat("Time data of the last 10 bars %s %s (ArrayPrint):",Symbol(),StringSubstr(EnumToString(Period()),7)); MqlDateTimePrint(array); /* Sample output: Time data of the last 10 bars GBPUSD H1 (ArrayPrint): [year] [mon] [day] [hour] [min] [sec] [day_of_week] [day_of_year] [0] 2023 7 17 7 0 0 1 197 [1] 2023 7 17 8 0 0 1 197 [2] 2023 7 17 9 0 0 1 197 [3] 2023 7 17 10 0 0 1 197 [4] 2023 7 17 11 0 0 1 197 [5] 2023 7 17 12 0 0 1 197 [6] 2023 7 17 13 0 0 1 197 [7] 2023 7 17 14 0 0 1 197 [8] 2023 7 17 15 0 0 1 197 [9] 2023 7 17 16 0 0 1 197 */ }
MqlDateTime構造体データを操作するための関数
上記のテストはすべて、便利で、実用的で、簡潔です。しかし、できれば同じ簡潔な表現が望ましいが、より完全な情報が必要な場合もあります。あるいは逆に、データ提示の簡潔さやドライさを減らすことで、より詳細な説明が必要になるかもしれません。例えば、日にちだけでは混乱するかもしれませんが、「木曜日」と書かれていれば、木曜日のことだとすぐに理解できます。月番号も同様で、どの月が7番目かを思い出すより、「07(7月)」と表示された方がいい場合もあります.。もちろんこれは大げさかもしれませんが、それでもこのような小さな改善が利便性を高めている。このような小さな便利さが積み重なることで、プログラムログの大量のエントリを分析する際に、非常に具体的な時間短縮につながります。
このような便利な機能を追加するには、MqlDateTimeフォーマットで日付の説明を返す独自の関数を書く必要があります。
その関数は、次をおこないます。
- 短いフォーマット(曜日、月、日、年、時間)でデータを表示する
- 表にデータを表示する(データヘッダ値)
構造体フィールドの説明を返す関数を作り始める前に、曜日と月の名前を返す補助関数を書きます。
補助関数
曜日名を取得するために、曜日を数値形式で格納する構造体フィールドの値に応じて曜日のテキストを返す簡単な関数を書いてみましょう。
//+------------------------------------------------------------------+ //| Return the name of a week day | //+------------------------------------------------------------------+ string DayWeek(MqlDateTime &date_time) { //--- Define a week day name string dw=EnumToString((ENUM_DAY_OF_WEEK)date_time.day_of_week); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(dw.Lower()) dw.SetChar(0,ushort(dw.GetChar(0)-0x20)); //--- Return a resulting string return dw; /* Sample output: Wednesday */ }
MQL5には曜日名のリストがあるので、ここでは列挙定数の文字列表現を使用します。テキストが正しく表示されるように、単語の最初の文字を除いて、行内のすべての文字を小文字に変換します。
月の名前を取得するために、数値形式で構造体フィールドに格納されている値に応じて月名のテキストを返す簡単な関数を書いてみましょう。
//+------------------------------------------------------------------+ //| Return a month name | //+------------------------------------------------------------------+ string Month(MqlDateTime &date_time) { //--- Define a month name switch(date_time.mon) { case 1 : return "January"; case 2 : return "February"; case 3 : return "March"; case 4 : return "April"; case 5 : return "May"; case 6 : return "June"; case 7 : return "July"; case 8 : return "August"; case 9 : return "September"; case 10 : return "October"; case 11 : return "November"; case 12 : return "December"; default : return "Undefined"; } /* Sample output: July */ }
MQL5には月を選択する列挙型がないので、ここでは構造体フィールドに書かれたデジタル値に応じて月名のテキストを選択して返すswitch演算子を使わなければなりません。
これらの関数は、曜日や月の説明を表示するのに役立つでしょう。また、将来、私たちの次のプロジェクトに役立つかもしれません。
MqlDateTime構造体フィールドの説明を返す関数は、「StringFormat():レビューと既成の例」で採用されている書式を持ちます。関数が返す各行は、ヘッダーとデータを持ちます。ヘッダーは左端からインデントすることができ、返されたレコードの表形式のビューのための幅を与えることができます。インデントと幅の値をパラメータとして関数に渡します。これらのオプションのデフォルト値はゼロです。つまり、パディングなしで、幅はヘッダーテキストの長さ+1に等しくなります。
MqlDateTime構造体の年:
//+------------------------------------------------------------------+ //| Return the year as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Year:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.year); /* Sample output: Year: 2023 */ }
MqlDateTime構造体の月:
//+------------------------------------------------------------------+ //| Return the month as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeMonth(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Month:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get a month name string mn=Month(date_time); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu (%s)",indent,"",w,header,date_time.mon,mn); /* Sample output: Month: 07 (July) */ }
MqlDateTime構造体の日:
//+------------------------------------------------------------------+ //| Return the day as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeDay(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.day); /* Sample output: Day: 19 */ }
MqlDateTime 構造体の時間:
//+------------------------------------------------------------------+ //| Return hours as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeHour(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Hour:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.hour); /* Sample output: Hour: 08 */ }
MqlDateTime構造体の分:
//+------------------------------------------------------------------+ //| Return minutes as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeMin(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Minutes:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.min); /* Sample output: Minutes: 41 */ }
MqlDateTime構造体の秒:
//+------------------------------------------------------------------+ //| Return seconds as a string from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeSec(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Seconds:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%02lu",indent,"",w,header,date_time.sec); /* Sample output: Seconds: 23 */ }
MqlDateTime構造体の曜日:
//+------------------------------------------------------------------+ //| Return a week day as a string from the MqlDateTime structure | //+------------------------------------------------------------------+ string MqlDateTimeDayWeek(MqlDateTime &date_time,const uint header_width=0,const uint indent=0,bool descr=true) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day of week:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get a week day name string dw=DayWeek(date_time); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s (%-lu)",indent,"",w,header,dw,date_time.day_of_week); /* Sample output: Day of week: Wednesday (3) */ }
MqlDateTime構造体の1年間の日数:
//+------------------------------------------------------------------+ //|Return a number of a day in a year from MqlDateTime | //+------------------------------------------------------------------+ string MqlDateTimeDayYear(MqlDateTime &date_time,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Day of year:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lu",indent,"",w,header,date_time.day_of_year); /* Sample output: Day of year: 199 */ }
使用例:
MqlDateTime構造体から日付時刻の短いレコードを表示するために、「DW, Month DD, YYYY, HH:MM:SS」フォーマットで日付を返す関数を書きます。
//+------------------------------------------------------------------+ //| Return the date as a string from the MqlDateTime structure | //| in the DW, Month DD, YYYY, HH:MM:SS format | //+------------------------------------------------------------------+ string DateTime(MqlDateTime &date_time) { //--- Get the month and the first three characters of a week day string mn=Month(date_time); string dw=StringSubstr(DayWeek(date_time),0,3); //--- Return a string in the DW, Month DD, YYYY, HH:MM:SS format return StringFormat("%s, %s %02lu, %lu, %02lu:%02lu:%02lu",dw,mn,date_time.day,date_time.year,date_time.hour,date_time.min,date_time.sec); /* Sample output: Wed, July 19, 2023, 08:41:23 */ }
これは、年の日数以外のすべての構造体データを1行でまとめたものです。この関数は、操作ログに一定数のバーを表示する場合などに便利です。
void OnStart() { datetime array[]; MqlDateTime adt[]; if(CopyTime(Symbol(),PERIOD_CURRENT,0,10,array)==10) { int total=(int)array.Size(); if(ArrayResize(adt,total)==total) { for(int i=0;i<total;i++) { ResetLastError(); if(!TimeToStruct(array[i],adt[i])) Print("TimeToStruct failed. Error: ",GetLastError()); PrintFormat("%s %s [%02u] %s",Symbol(),StringSubstr(EnumToString(Period()),7),i,DateTime(adt[i])); } } } /* Sample output: GBPUSD H1 [00] Wed, July 19, 2023, 02:00:00 GBPUSD H1 [01] Wed, July 19, 2023, 03:00:00 GBPUSD H1 [02] Wed, July 19, 2023, 04:00:00 GBPUSD H1 [03] Wed, July 19, 2023, 05:00:00 GBPUSD H1 [04] Wed, July 19, 2023, 06:00:00 GBPUSD H1 [05] Wed, July 19, 2023, 07:00:00 GBPUSD H1 [06] Wed, July 19, 2023, 08:00:00 GBPUSD H1 [07] Wed, July 19, 2023, 09:00:00 GBPUSD H1 [08] Wed, July 19, 2023, 10:00:00 GBPUSD H1 [09] Wed, July 19, 2023, 11:00:00 */ }
次の関数を実装して、構造体のすべてのフィールドを短い表形式で記録してみましょう。
//+------------------------------------------------------------------+ //| Logs descriptions of all fields of the MqlDateTime structure | //+------------------------------------------------------------------+ void MqlDateTimePrint(MqlDateTime &date_time,const bool short_entry=true,const uint header_width=0,const uint indent=0) { //--- If it is a short entry, log the date and time in the DW, Month DD, YYYY, HH:MM:SS format if(short_entry) Print(DateTime(date_time)); /* Sample output: Wed, July 19, 2023, 08:41:23 */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field string res=StringFormat("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s", MqlDateTimeYear(date_time,header_width,indent), MqlDateTimeMonth(date_time,header_width,indent), MqlDateTimeDay(date_time,header_width,indent), MqlDateTimeHour(date_time,header_width,indent), MqlDateTimeMin(date_time,header_width,indent), MqlDateTimeSec(date_time,header_width,indent), MqlDateTimeDayWeek(date_time,header_width,indent), MqlDateTimeDayYear(date_time,header_width,indent) ); //--- Display the obtained string in the journal Print(res); } /* Sample output: Year: 2023 Month: 07 (July) Day: 19 Hour: 09 Minutes: 32 Seconds: 25 Day of week: Wednesday (3) Day of year: 199 */ }
次は、関数の処理例を示す関数です。まず、操作ログに短いエントリを表示し、その後に、フィールドヘッダーを字下げし、フィールド幅をそれぞれ2文字と14文字とした表形式を表示します。
void OnStart() { MqlDateTime dt; TimeCurrent(dt); MqlDateTimePrint(dt,true); MqlDateTimePrint(dt,false,14,2); /* Sample output: Wed, July 19, 2023, 09:33:56 Year: 2023 Month: 07 (July) Day: 19 Hour: 09 Minutes: 33 Seconds: 56 Day of week: Wednesday (3) Day of year: 199 */ }
上記で紹介したMqlDateTime構造体のフィールドや補助的なフィールドを操作するための関数はすべて、ご自分のプログラムで「そのまま」使用することも、ビジョンやニーズに応じて変更することもできます。
MqlTick構造体
最終価格を銘柄ごとに格納するための構造体は、現在の価格に関する最も必要なデータをタイムリーに取得するように設計されています。
struct MqlTick { datetime time; // Last price update time double bid; // Current Bid price double ask; // Current Ask price double last; // Current price of the last trade (Last) ulong volume; // Volume for the current Last price long time_msc; // Last price update time in milliseconds uint flags; // Tick flags double volume_real; // Volume for the current Last price };
MqlTick型の変数を使用すると、SymbolInfoTick()関数を1回呼び出すだけで、Ask、Bid、Last、Volumeの値とミリ秒単位の時間を取得できます。
各ティックのパラメータは、前のティックと比べて変化があるかどうかに関係なく記入されます。そのため、ティック履歴で過去の値を検索することなく、過去のどの時点の正しい価格も知ることができます。たとえば、1ティック到着中に買値だけが変化しても、その構造体には、直前の売値や出来高など、他のパラメータも含まれています。
ティックフラグを分析し、どのデータが変更されたかを調べます。
- TICK_FLAG_BID - ティックが買値を変更
- TICK_FLAG_ASK - ティックが売値を変更
- TICK_FLAG_LAST:ティックが最後の取引価格を変更
- TICK_FLAG_VOLUME - ティックがボリュームを変更
- TICK_FLAG_BUY - ティックは買い取引の結果
- TICK_FLAG_SELL - ティックは売り取引の結果
MqlTick、表示メソッド
ArrayPrint()関数は、MqlDateTimeと同じように操作ログに構造体を表示するのに適しています。
void OnStart() { //--- Declare a variable with the MqlTick type MqlTick tick; //--- If failed to get the last tick, display the error message and exit the method if(!SymbolInfoTick(Symbol(),tick)) { Print("SymbolInfoTick failed, error: ",(string)GetLastError()); return; } //--- Display the tick using standard ArrayPrint() //--- To do this, declare an array of dimension 1 with type MqlTick, //--- enter the value of the 'tick' variable into it and print it MqlTick array[1]; array[0]=tick; Print("Last tick (ArrayPrint):"); ArrayPrint(array); /* Sample output: Last tick (ArrayPrint): [time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real] [0] 2023.07.19 17:02:49 1.28992 1.28996 0.0000 0 1689786169589 6 0.00000 */ }
配列を表示するには、その配列にティックの範囲を記入すればよいのです。
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If failed to get the last 10 ticks, display the error message and exit the method if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 10 tick (ArrayPrint):"); ArrayPrint(array); /* Sample output: Last 10 tick (ArrayPrint): [time] [bid] [ask] [last] [volume] [time_msc] [flags] [volume_real] [0] 2023.07.19 17:24:38 1.28804 1.28808 0.0000 0 1689787478461 6 0.00000 [1] 2023.07.19 17:24:38 1.28806 1.28810 0.0000 0 1689787478602 6 0.00000 [2] 2023.07.19 17:24:38 1.28804 1.28808 0.0000 0 1689787478932 6 0.00000 [3] 2023.07.19 17:24:39 1.28806 1.28810 0.0000 0 1689787479210 6 0.00000 [4] 2023.07.19 17:24:39 1.28807 1.28811 0.0000 0 1689787479765 6 0.00000 [5] 2023.07.19 17:24:39 1.28808 1.28812 0.0000 0 1689787479801 6 0.00000 [6] 2023.07.19 17:24:40 1.28809 1.28813 0.0000 0 1689787480240 6 0.00000 [7] 2023.07.19 17:24:40 1.28807 1.28811 0.0000 0 1689787480288 6 0.00000 [8] 2023.07.19 17:24:40 1.28809 1.28813 0.0000 0 1689787480369 6 0.00000 [9] 2023.07.19 17:24:40 1.28810 1.28814 0.0000 0 1689787480399 6 0.00000 */ }
繰り返しになりますが、もっと意味のある値の表示が必要です。例えば、ミリ秒単位の時間やフラグなどです。時刻は時刻形式で、フラグは列挙定数形式など、普通のやり方で表示するのが便利でしょう。
MqlTick構造体データを操作するための関数
MqlTick構造体データを操作するための関数を実装してみましょう。MqlDateTime構造体を操作するために既に作成されたすべての関数と同様に、MqlTickを操作するための関数は、フォーマットされた文字列を返します。行のフォーマットには、テキストの左証拠金とヘッダーフィールドの幅が含まれます。デフォルトでは、パディングと証拠金幅の値はゼロになります。つまり、パディングはなく、証拠金幅はヘッダーテキストの長さ+1に等しくなります。
補助関数
ミリ秒単位の時間を文字列として返す関数はすでに書きました。ここでは、ティック時間をミリ秒単位で返すのに便利です。応用してみましょう。
//+------------------------------------------------------------------+ //| Accept a date in ms, return time in Date Time.Msc format | //+------------------------------------------------------------------+ string TimeMSC(const long time_msc) { return StringFormat("%s.%.3hu",string((datetime)time_msc / 1000),time_msc % 1000); /* Sample output: 2023.07.13 09:31:58.177 */ }
MqlTick構造体の時間:
//+------------------------------------------------------------------+ //| Return the time of the last price update as a string | //+------------------------------------------------------------------+ string MqlTickTime(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)tick.time); /* Sample output: Time: 2023.07.19 20:58:00 */ }
MqlTick構造体の買値:
//+------------------------------------------------------------------+ //| Return the Bid price as a string | //+------------------------------------------------------------------+ string MqlTickBid(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Bid:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.bid); /* Sample output: Bid: 1.29237 */ }
MqlTick構造体の売値:
//+------------------------------------------------------------------+ //| Return the Ask price as a string | //+------------------------------------------------------------------+ string MqlTickAsk(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Ask:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.ask); /* Sample output: Ask: 1.29231 */ }
MqlTick構造体の最後の取引価格:
//+------------------------------------------------------------------+ //| Return the Last price as a string | //+------------------------------------------------------------------+ string MqlTickLast(const string symbol,const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Last:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,tick.last); /* Sample output: Last: 0.00000 */ }
MqlTick構造体の最終価格ボリューム:
//+------------------------------------------------------------------+ //| Return the volume for the Last price as a string | //+------------------------------------------------------------------+ string MqlTickVolume(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-I64u",indent,"",w,header,tick.volume); /* Sample output: Volume: 0 */ }
MqlTick構造体のミリ秒単位の時間:
//+------------------------------------------------------------------+ //| Return the time in milliseconds as a string | //+------------------------------------------------------------------+ string MqlTickTimeMSC(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time msc:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,TimeMSC(tick.time_msc)); /* Sample output: Time msc: 2023.07.19 21:21:09.732 */ }
MqlTick構造体のティックフラグ:
//+------------------------------------------------------------------+ //| Return tick flags as a string | //+------------------------------------------------------------------+ string MqlTickFlags(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Flags:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Define a variable to describe tick flags string flags=""; //--- Parse tick flags into components if((tick.flags & TICK_FLAG_BID)==TICK_FLAG_BID) flags+=(flags.Length()>0 ? "|" : "")+"BID"; if((tick.flags & TICK_FLAG_ASK)==TICK_FLAG_ASK) flags+=(flags.Length()>0 ? "|" : "")+"ASK"; if((tick.flags & TICK_FLAG_LAST)==TICK_FLAG_LAST) flags+=(flags.Length()>0 ? "|" : "")+"LAST"; if((tick.flags & TICK_FLAG_VOLUME)==TICK_FLAG_VOLUME) flags+=(flags.Length()>0 ? "|" : "")+"VOLUME"; if((tick.flags & TICK_FLAG_BUY)==TICK_FLAG_BUY) flags+=(flags.Length()>0 ? "|" : "")+"BUY"; if((tick.flags & TICK_FLAG_SELL)==TICK_FLAG_SELL) flags+=(flags.Length()>0 ? "|" : "")+"SELL"; //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,flags); /* Sample output: Flags: BID|ASK */ }
MqlTick構造体の精度を高めた最終価格ボリューム:
//+------------------------------------------------------------------+ //| Return the volume for the Last price as a string | //+------------------------------------------------------------------+ string MqlTickVolumeReal(const MqlTick &tick,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume Real:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.2f",indent,"",w,header,tick.volume_real); /* Sample output: Volume Real: 0.00 */ }
使用例
ティックデータを操作ログに表示する関数を書きます。操作ログに表示される価格の精度を知るために、銘柄名を関数に渡します。VolumeフィールドとVolume Realフィールドには、最終価格ボリュームが含まれているため、Lastがゼロ(翻訳されていない)であれば、ボリュームを表示する意味はありません。ティックの配列からティックのインデックスを指定して表示できるようにするために、関数の入力パラメータにこのインデックスを渡します。デフォルトは-1であり、この値ではインデックスは表示されません。
//+------------------------------------------------------------------+ //| Logs descriptions of all fields of the MqlTick structure | //| If Last==0, Last, Volume and Volume Real fields are not displayed| //+------------------------------------------------------------------+ void MqlTickPrint(const string symbol,const MqlTick &tick,const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE) { //--- Declare the variable for storing the result string res=""; //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); string num=(index==WRONG_VALUE ? "" : StringFormat("[%ld] ",index)); //--- If it is a short entry, log the tick data in the Symbol TimeMSC, Bid, Ask, Last, Vol/VolR, Flags format if(short_entry) { //--- If Last is not zero, display Last, Volume and Volume Real, otherwise they are all zero and there is no point in displaying them string last=(tick.last!=0 ? StringFormat(", Last: %.*f, Vol: %I64u/%.2f",dg,tick.last,tick.volume,tick.volume_real) : ""); res=StringFormat("%sTick %s Time: %s, Bid: %.*f, Ask: %.*f%s, %s",num,symbol,TimeMSC(tick.time_msc),dg,tick.bid,dg,tick.ask,last,MqlTickFlags(tick)); Print(res); } /* Sample output (if Last is not zero): Tick GBPUSD Time: 2023.07.20 13:57:31.376, Bid: 1.28947, Ask: 1.28951, Last: 1.28947, Vol: 33/33.45, Flags: BID|ASK Sample output (if Last is zero): Tick GBPUSD Time: 2023.07.20 13:59:33.274, Bid: 1.28956, Ask: 1.28960, Flags: BID|ASK */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field res=StringFormat("%s\n%s\n%s%s%s\n%s\n%s%s", MqlTickTime(tick,header_width,indent), MqlTickBid(symbol,tick,header_width,indent), MqlTickAsk(symbol,tick,header_width,indent), (tick.last!=0 ? "\n"+MqlTickLast(symbol,tick,header_width,indent) : ""), (tick.last!=0 ? "\n"+MqlTickVolume(tick,header_width,indent) : ""), MqlTickTimeMSC(tick,header_width,indent), MqlTickFlags(tick,header_width,indent), (tick.last!=0 ? "\n"+MqlTickVolumeReal(tick,header_width,indent) : "") ); //--- Display the obtained string in the journal Print(res); } /* Sample output (if Last is not zero): Time: 2023.07.20 14:42:33 Bid: 1.28958 Ask: 1.28962 Last: 1.28947 Volume: 33 Time msc: 2023.07.20 14:42:33.401 Flags: BID|ASK Volume Real: 33.45 Sample output (if Last is zero): Time: 2023.07.20 14:42:33 Bid: 1.28958 Ask: 1.28962 Time msc: 2023.07.20 14:42:33.401 Flags: BID|ASK */ }
次は、直近の10ティックを、配列からのティックインデックスを示す短い形式で操作ログに出力する関数です。
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If failed to get the last 10 ticks, display the error message and exit the method if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,10)!=10) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 10 tick (MqlTickPrint):"); for(int i=0;i<(int)array.Size();i++) MqlTickPrint(Symbol(),array[i],true,0,0,i); /* Sample output: Last 10 tick (MqlTickPrint): [0] Tick GBPUSD Time: 2023.07.20 15:36:29.941, Bid: 1.28686, Ask: 1.28690, Flags: BID|ASK [1] Tick GBPUSD Time: 2023.07.20 15:36:29.970, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK [2] Tick GBPUSD Time: 2023.07.20 15:36:30.061, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK [3] Tick GBPUSD Time: 2023.07.20 15:36:30.212, Bid: 1.28688, Ask: 1.28692, Flags: BID|ASK [4] Tick GBPUSD Time: 2023.07.20 15:36:30.259, Bid: 1.28689, Ask: 1.28693, Flags: BID|ASK [5] Tick GBPUSD Time: 2023.07.20 15:36:30.467, Bid: 1.28682, Ask: 1.28686, Flags: BID|ASK [6] Tick GBPUSD Time: 2023.07.20 15:36:30.522, Bid: 1.28681, Ask: 1.28685, Flags: BID|ASK [7] Tick GBPUSD Time: 2023.07.20 15:36:30.572, Bid: 1.28673, Ask: 1.28677, Flags: BID|ASK [8] Tick GBPUSD Time: 2023.07.20 15:36:30.574, Bid: 1.28672, Ask: 1.28676, Flags: BID|ASK [9] Tick GBPUSD Time: 2023.07.20 15:36:30.669, Bid: 1.28674, Ask: 1.28678, Flags: BID|ASK */ }
次は、左インデント2文字、ヘッダーフィールド幅14文字で、配列の最後の4ティックをログに表示する関数です。
void OnStart() { //--- Declare a dynamic array of the MqlTick type MqlTick array[]; //--- If the last 4 ticks are not received in the array, display an error message and leave if(CopyTicks(Symbol(),array,COPY_TICKS_ALL,0,4)!=4) { Print("CopyTicks failed, error: ",(string)GetLastError()); return; } Print("Last 4 tick (MqlTickPrint):"); for(int i=0;i<(int)array.Size();i++) { PrintFormat("Tick[%lu] %s:",i,Symbol()); MqlTickPrint(Symbol(),array[i],false,14,2); } /* Sample output: Last 4 tick (MqlTickPrint): Tick[0] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28776 Ask: 1.28780 Time msc: 2023.07.20 17:04:51.203 Flags: BID|ASK Tick[1] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28772 Ask: 1.28776 Time msc: 2023.07.20 17:04:51.331 Flags: BID|ASK Tick[2] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28771 Ask: 1.28775 Time msc: 2023.07.20 17:04:51.378 Flags: BID|ASK Tick[3] GBPUSD: Time: 2023.07.20 17:04:51 Bid: 1.28772 Ask: 1.28776 Time msc: 2023.07.20 17:04:51.680 Flags: BID|ASK */ }
MqlRates構造体
以下は価格、数量、スプレッドの情報を格納するための構造体です。
struct MqlRates { datetime time; // period start time double open; // open price double high; // high price for the period double low; // low price for the period double close; // close price long tick_volume; // tick volume int spread; // spread long real_volume; // exchange volume };
MqlRates、表示メソッド
MqlRatesは、過去のデータの単一バーのデータを保存するための構造体です。この構造体は、CopyRates()関数を使って埋めることができます。現在のバーのデータを取得するには、インデックスを0、コピーしたバーの数を1として、関数呼び出しの最初のフォームを使用することができます。いずれにせよ、この関数はMqlRates型で配列を埋めます。これは、ArrayPrint()を使ってこの配列を操作ログに表示するのが便利だという結論につながります。
void OnStart() { //--- MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,1,array)!=1) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } Print("Current bar ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):"); ArrayPrint(array); /* Sample output: Current bar GBPUSD H1 (ArrayPrint): [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2023.07.21 04:00:00 1.28763 1.28765 1.28663 1.28748 2083 7 0 */ }
したがって、直近の10本のバーをコピーするには、コピーするデータ数を10に等しく指定するだけでよくなります。
void OnStart() { //--- MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } Print("Data of the last 10 bars: ",Symbol()," ",StringSubstr(EnumToString(Period()),7)," (ArrayPrint):"); ArrayPrint(array); /* Sample output: Data of the last 10 bars: GBPUSD H1 (ArrayPrint): [time] [open] [high] [low] [close] [tick_volume] [spread] [real_volume] [0] 2023.07.20 20:00:00 1.28530 1.28676 1.28512 1.28641 2699 4 0 [1] 2023.07.20 21:00:00 1.28641 1.28652 1.28557 1.28587 1726 3 0 [2] 2023.07.20 22:00:00 1.28587 1.28681 1.28572 1.28648 2432 3 0 [3] 2023.07.20 23:00:00 1.28648 1.28683 1.28632 1.28665 768 4 0 [4] 2023.07.21 00:00:00 1.28663 1.28685 1.28613 1.28682 396 1 0 [5] 2023.07.21 01:00:00 1.28684 1.28732 1.28680 1.28714 543 8 0 [6] 2023.07.21 02:00:00 1.28714 1.28740 1.28690 1.28721 814 2 0 [7] 2023.07.21 03:00:00 1.28721 1.28774 1.28685 1.28761 2058 5 0 [8] 2023.07.21 04:00:00 1.28763 1.28791 1.28663 1.28774 3480 7 0 [9] 2023.07.21 05:00:00 1.28774 1.28776 1.28769 1.28774 18 7 0 */ }
すべてが同じです。操作ログには長いデータのリストがあります。テーブルのヘッダーが操作ログウィンドウの上端に隠れてしまうと、表示されている数字が何を指しているのかわからなくなってしまいます。
構造体フィールドの説明を返して、このデータをターミナル操作ログに表示する独自の関数を書いてみましょう。
MqlRates構造体データを操作するための関数
私たちのカスタム関数は、構造体の各フィールドのテキスト説明を返します。各記述にはヘッダーと実際のデータがあります。関数から返された文字列に対して、左端からのインデントとヘッダーフィールドの幅を設定することができます。
Time
Timeは、期間の開始時間です。言い換えれば、構造体に書き込まれたデータが要求された銘柄とチャート期間のバーの開始時間です。
//+------------------------------------------------------------------+ //| Return the bar opening time as a string | //+------------------------------------------------------------------+ string MqlRatesTime(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Time:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,(string)rates.time); /* Sample output: Time: 2023.07.21 06:00:00 */ }
Open
構造体に書き込まれたデータが要求された銘柄とチャート期間のバー始値です。
//+------------------------------------------------------------------+ //| Return the bar open price as a string | //+------------------------------------------------------------------+ string MqlRatesOpen(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Open:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.open); /* Sample output: Open: 1.28812 */ }
High
高値 - 構造体に書き込まれたデータが要求された、銘柄とチャート期間のバーの最高値です。
//+------------------------------------------------------------------+ //| Return the High bar price as a string | //+------------------------------------------------------------------+ string MqlRatesHigh(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="High:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.high); /* Sample output: High: 1.28859 */ }
Low
安値 - 構造体に書き込まれたデータが要求された銘柄とチャート期間のバーの最安値です。
//+------------------------------------------------------------------+ //| Return the bar Low price as a string | //+------------------------------------------------------------------+ string MqlRatesLow(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Low:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.low); /* Sample output: Low: 1.28757 */ }
Close
終値 - 構造体に書き込まれたデータが要求された銘柄とチャート期間のバーの終値です。
現在のバーの終値は、チャートがどの価格に基づいているかに応じて、現在の買値または最終価格と等しくなります。
//+------------------------------------------------------------------+ //| Return the bar close price as a string | //+------------------------------------------------------------------+ string MqlRatesClose(const string symbol,const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Close:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,rates.close); /* Sample output: Close: 1.28770 */ }
TickVolume
バーのティックボリュームです。
//+------------------------------------------------------------------+ //| Return the tick volume of a bar as a string | //+------------------------------------------------------------------+ string MqlRatesTickVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Tick Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.tick_volume); /* Sample output: Tick Volume: 963 */ }
Spread
バーのスプレッドです。
//+------------------------------------------------------------------+ //| Return the bar spread as a string | //+------------------------------------------------------------------+ string MqlRatesSpread(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Spread:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-ld",indent,"",w,header,rates.spread); /* Sample output: Spread: 4 */ }
RealVolume
バーの取引量です。
//+------------------------------------------------------------------+ //| Return the bar exchange volume as a string | //+------------------------------------------------------------------+ string MqlRatesRealVolume(const MqlRates &rates,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Real Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,rates.real_volume); /* Sample output: Real Volume: 0 */ }
使用例
操作ログに過去10本のバーのデータを表示する関数を書いてみましょう。
void OnStart() { //--- Copy the last 10 data bars to the MqlRates array MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,10,array)!=10) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } //--- Set the indexing of the array like a timeseries ArraySetAsSeries(array,true); //--- Print short entries in the journal in a loop through the array with the received bar data for(int i=0;i<(int)array.Size();i++) MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],true,0,0,i); /* Sample output: GBPUSD H1[0]: 2023.07.21 14:00:00, O: 1.28451, H: 1.28541, L: 1.28451, C: 1.28501, S: 4, V: 821, RV: 0 GBPUSD H1[1]: 2023.07.21 13:00:00, O: 1.28678, H: 1.28685, L: 1.28418, C: 1.28452, S: 1, V: 3602, RV: 0 GBPUSD H1[2]: 2023.07.21 12:00:00, O: 1.28581, H: 1.28696, L: 1.28557, C: 1.28678, S: 1, V: 4807, RV: 0 GBPUSD H1[3]: 2023.07.21 11:00:00, O: 1.28695, H: 1.28745, L: 1.28401, C: 1.28581, S: 1, V: 7440, RV: 0 GBPUSD H1[4]: 2023.07.21 10:00:00, O: 1.28933, H: 1.28960, L: 1.28651, C: 1.28696, S: 1, V: 8883, RV: 0 GBPUSD H1[5]: 2023.07.21 09:00:00, O: 1.28788, H: 1.29040, L: 1.28753, C: 1.28934, S: 1, V: 5474, RV: 0 GBPUSD H1[6]: 2023.07.21 08:00:00, O: 1.28794, H: 1.28848, L: 1.28713, C: 1.28787, S: 1, V: 1885, RV: 0 GBPUSD H1[7]: 2023.07.21 07:00:00, O: 1.28762, H: 1.28808, L: 1.28744, C: 1.28794, S: 4, V: 878, RV: 0 GBPUSD H1[8]: 2023.07.21 06:00:00, O: 1.28812, H: 1.28859, L: 1.28743, C: 1.28760, S: 3, V: 1112, RV: 0 GBPUSD H1[9]: 2023.07.21 05:00:00, O: 1.28774, H: 1.28820, L: 1.28747, C: 1.28812, S: 7, V: 1671, RV: 0 */ }
必要な量のデータを配列にコピーした後、それを時系列のようにインデックス付けして、データがターミナルでチャートの棒グラフと同じように表示されるようにします。インデックスがゼロのデータは現在のバーに対応します。
この関数は、操作ログの最後の4バーを、ヘッダーフィールドを2文字左にインデントし、タイトルフィールドの幅を14文字にして、表形式で表示します。
void OnStart() { //--- Copy the last 4 data bars to the MqlRates array MqlRates array[]; if(CopyRates(Symbol(),PERIOD_CURRENT,0,4,array)!=4) { Print("CopyRates failed, error: ",(string)GetLastError()); return; } //--- Set the indexing of the array like a timeseries ArraySetAsSeries(array,true); //--- Print short entries in the journal in a loop through the array with the received bar data for(int i=0;i<(int)array.Size();i++) MqlRatesPrint(Symbol(),PERIOD_CURRENT,array[i],false,14,2,i); /* Sample output: GBPUSD H1[0]: Time: 2023.07.21 14:00:00 Open: 1.28451 High: 1.28541 Low: 1.28451 Close: 1.28491 Tick Volume: 1098 Spread: 4 Real Volume: 0 GBPUSD H1[1]: Time: 2023.07.21 13:00:00 Open: 1.28678 High: 1.28685 Low: 1.28418 Close: 1.28452 Tick Volume: 3602 Spread: 1 Real Volume: 0 GBPUSD H1[2]: Time: 2023.07.21 12:00:00 Open: 1.28581 High: 1.28696 Low: 1.28557 Close: 1.28678 Tick Volume: 4807 Spread: 1 Real Volume: 0 GBPUSD H1[3]: Time: 2023.07.21 11:00:00 Open: 1.28695 High: 1.28745 Low: 1.28401 Close: 1.28581 Tick Volume: 7440 Spread: 1 Real Volume: 0 */ }
MqlBookInfo構造体
市場深度データを提供する構造体です。
struct MqlBookInfo { ENUM_BOOK_TYPE type; // order type from ENUM_BOOK_TYPE enumeration double price; // price long volume; // volume double volume_real; // volume with increased accuracy };
この構造体を使うには、この型の変数を宣言するだけで済みます。市場深度はすべての金融商品について利用できるわけではありません。市場深度のデータを受信する前に、MarketBookAdd() を使用して購読する必要があります。完了したら、MarketBookRelease()を使用して、購読を解除します。EAプログラムには、受信された通知を処理するOnBookEvent() void関数を含める必要があります。
MqlBookInfo、表示メソッド
市場深度の各受信には、その中の注文リストの受信が含まれます。これはデータ配列です。したがって、ArrayPrint() を使用して、市場深度のスナップショットを表示できます。
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print the header in the journal and the market depth snapshot from the array below Print("MarketBookInfo by ",Symbol(),":"); ArrayPrint(array); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: MarketBookInfo by GBPUSD: [type] [price] [volume] [volume_real] [0] 1 1.28280 100 100.00000 [1] 1 1.28276 50 50.00000 [2] 1 1.28275 20 20.00000 [3] 1 1.28273 10 10.00000 [4] 2 1.28268 10 10.00000 [5] 2 1.28266 20 20.00000 [6] 2 1.28265 50 50.00000 [7] 2 1.28260 100 100.00000 */ }
おわかりのように、ここでのリクエストの種類は数値で表されており、これは知覚するのに不便です。市場深度フィールドに関する記述を返す関数を、前述した他の構造体ですでに受け入れられているスタイルで書いてみましょう。
MqlBookInfo構造体データを操作するための関数
MqlBookInfo構造体のフィールドの文字列表現を返すすべての関数は、対応する構造体のフィールドを記述するために上で説明した関数と同じスタイルになります。これらのメソッドについて考えてみましょう。
MqlBookInfo市場深度構造体の注文タイプ:
//+------------------------------------------------------------------+ //| Return the order type in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoType(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Get the value of the order type ENUM_BOOK_TYPE book_type=book.type; //--- "Cut out" the type from the string obtained from enum string type=StringSubstr(EnumToString(book_type),10); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(type.Lower()) type.SetChar(0,ushort(type.GetChar(0)-0x20)); //--- Replace all underscore characters with space in the resulting line StringReplace(type,"_"," "); //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Type:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-s",indent,"",w,header,type); /* Sample output: Type: Sell */ }
MqlBookInfo市場深度構造体の注文価格:
//+------------------------------------------------------------------+ //| Return the order price in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoPrice(const string symbol,const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Price:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Get the number of decimal places int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.*f",indent,"",w,header,dg,book.price); /* Sample output: Price: 1.28498 */ }
MqlBookInfo市場深度構造体の注文量:
//+------------------------------------------------------------------+ //| Return the order volume in the market depth as a string | //+------------------------------------------------------------------+ string MqlBookInfoVolume(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-lld",indent,"",w,header,book.volume); /* Sample output: Volume: 100 */ }
正確さを増したボリューム:
//+------------------------------------------------------------------+ //| Return the order volume with increased accuracy as a string | //+------------------------------------------------------------------+ string MqlBookInfoVolumeReal(const MqlBookInfo &book,const uint header_width=0,const uint indent=0) { //--- Define the header text and the width of the header field //--- If the header width is passed to the function equal to zero, then the width will be the size of the header line + 1 string header="Volume Real:"; uint w=(header_width==0 ? header.Length()+1 : header_width); //--- Return the property value with a header having the required width and indentation return StringFormat("%*s%-*s%-.2f",indent,"",w,header,book.volume_real); /* Sample output: Volume Real: 100.00 */ }
使用例:
では、MqlBookInfo構造体のすべてのデータを操作ログに出力する関数を書いてみましょう。一行形式と表形式の2種類の表示が可能です。
//+------------------------------------------------------------------+ //| Logs a description of all fields of the MqlRates structure | //+------------------------------------------------------------------+ void MqlBookInfoPrint(const string symbol,const MqlBookInfo &book, const bool short_entry=true,const uint header_width=0,const uint indent=0,int index=WRONG_VALUE) { //--- Declare the variable for storing the result string res=""; //--- Get the number of decimal places and the string index value int dg=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); string num=(index==WRONG_VALUE ? "" : StringFormat("[%02ld]",index)); //--- "Cut out" the type from the order type name string obtained from enum string type=StringSubstr(EnumToString(book.type),10); //--- Convert all obtained symbols to lower case and replace the first letter from small to capital if(type.Lower()) type.SetChar(0,ushort(type.GetChar(0)-0x20)); //--- Replace all underscore characters with space in the resulting line StringReplace(type,"_"," "); //--- If it is a short entry, log the market depth data in the [index] Type Price V VR format if(short_entry) { res=StringFormat("%-8s%-11s%- *.*f Volume%- 5lld Real%- 8.2f", num,type,dg+4,dg,book.price,book.volume,book.volume_real); Print(res); } /* Sample output: [00] Sell 1.28598 Volume 100 Real 100.00 */ //--- Otherwise else { //--- create a string describing all the data of the structure with indents and a given width of the header field res=StringFormat("Market Book by %s %s:\n%s\n%s\n%s\n%s",symbol,num, MqlBookInfoType(book,header_width,indent), MqlBookInfoPrice(symbol,book,header_width,indent), MqlBookInfoVolume(book,header_width,indent), MqlBookInfoVolumeReal(book,header_width,indent) ); //--- Display the obtained string in the journal Print(res); } /* Sample output BoolInfo by GBPUSD [00]: Type: Sell Price: 1.28588 Volume: 100 Volume Real: 100.00 */ }
市場深度は単一の注文ではなく、これらの注文のリストを配列で受け取るため、ここでのメインモードは、操作ログへの出力を1行にまとめることです。従って、この配列を操作ログに表示するには、以下の関数を使います。
//+----------------------------------------------------------------------+ //| Display the market depth entries in the journal in the short format | //+----------------------------------------------------------------------+ void MqlBookInfoPrintShort(const string symbol,const MqlBookInfo &book_array[]) { PrintFormat("Market Book by %s:",symbol); for(int i=0;i<(int)book_array.Size();i++) MqlBookInfoPrint(symbol,book_array[i],true,0,0,i); }
この関数は、市場深度の注文の配列を受け取り、その配列をループして、短い出力を使用して、すべての市場深度データを操作ログに表示します。
次は、この関数の使い方と結果を示す関数です。
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print in the journal a snapshot of the market depth from the array in the form of strings MqlBookInfoPrintShort(Symbol(),array); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: Market Book by GBPUSD: [00] Sell 1.28674 Volume 100 Real 100.00 [01] Sell 1.28668 Volume 50 Real 50.00 [02] Sell 1.28666 Volume 20 Real 20.00 [03] Sell 1.28664 Volume 10 Real 10.00 [04] Buy 1.28657 Volume 10 Real 10.00 [05] Buy 1.28654 Volume 20 Real 20.00 [06] Buy 1.28653 Volume 50 Real 50.00 [07] Buy 1.28646 Volume 100 Real 100.00 */ }
しかし、同じデータを表形式で表示する必要がある場合もあります。そのためには、次の関数を使うことができます。
//+------------------------------------------------------------------------+ //| Display the market depth entries in the journal in the tabular format | //+------------------------------------------------------------------------+ void MqlBookInfoPrintTable(const string symbol,const MqlBookInfo &book_array[],const uint header_width=0,const uint indent=0) { for(int i=0;i<(int)book_array.Size();i++) MqlBookInfoPrint(symbol,book_array[i],false,header_width,indent,i); }
次は、この関数の使い方と結果を示す関数です。
void OnStart() { //--- Declare an array to store a snapshot of the market depth MqlBookInfo array[]; //--- If unable to open the market depth and subscribe to its events, inform of that and leave if(!MarketBookAdd(Symbol())) { Print("MarketBookAdd failed, error: ",(string)GetLastError()); return; } //--- If unable to obtain the market depth entries, inform of that and leave if(!MarketBookGet(Symbol(),array)) { Print("MarketBookGet failed, error: ",(string)GetLastError()); return; } //--- Print in the journal a snapshot of the market depth from the array in the form of strings MqlBookInfoPrintTable(Symbol(),array,14,2); //--- If unable to unsubscribe from the market depth, send an error message to the journal if(!MarketBookRelease(Symbol())) Print("MarketBookRelease failed, error: ",(string)GetLastError()); /* Sample output: Market Book by GBPUSD [00]: Type: Sell Price: 1.28627 Volume: 100 Volume Real: 100.00 Market Book by GBPUSD [01]: Type: Sell Price: 1.28620 Volume: 50 Volume Real: 50.00 Market Book by GBPUSD [02]: Type: Sell Price: 1.28618 Volume: 20 Volume Real: 20.00 Market Book by GBPUSD [03]: Type: Sell Price: 1.28615 Volume: 10 Volume Real: 10.00 Market Book by GBPUSD [04]: Type: Buy Price: 1.28610 Volume: 10 Volume Real: 10.00 Market Book by GBPUSD [05]: Type: Buy Price: 1.28606 Volume: 20 Volume Real: 20.00 Market Book by GBPUSD [06]: Type: Buy Price: 1.28605 Volume: 50 Volume Real: 50.00 Market Book by GBPUSD [07]: Type: Buy Price: 1.28599 Volume: 100 Volume Real: 100.00 */ }
結論
今回は、MqlDateTime、MqlTick、MqlRates、MqlBookInfoの4つの構造体のフィールドの表示について考えました。作成された関数は、各構造体のフィールドの説明をHeader-Data形式の文字列として返し、表示したり別の関数内で使用したりできます。すべての関数は自立しており、カスタムプログラムですぐに「そのまま」使用できます。次のステップは、取引構造体の説明と表示です。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/12900
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索