どうも!和菓子職人トレーダー潤奈です( ゚Д゚)
今回はMT4に記録されている指定した期間の取引履歴をCSV出力するスクリプトを作成したいと思います。
MetaEditorで作成
今回のコードはスクリプトになりますので、MetaEditorで作成する際には「スクリプト」を選択して作成して下さい。
各コード説明
プロパティを追加
上から4行は作成された時点で記載されていますので、追加するのは5行目の#property show_inputsです。
1 2 3 4 5 |
#property copyright "Copyright 2023, 潤奈FX" #property link "https://zyunafx.com/" #property version "1.00" #property strict #property show_inputs //スクリプト実行前にパラメータ設定ウインドウを開く |
このshow_inputsを設定しておくと、スクリプト実行前にパラメータ等の設定ウインドウが開きます。
EAやインジケーターでは必ず表示される画面ですが、スクリプトではこの設定をしておかないとパラメータ等の設定ウインドウが開かずに処理を開始してしまいます。
パラメーターを設定
今回はシンプルに出力する取引期間(決済時間基準)の開始と終了の年月日を選択できるようにします。
1 2 |
input datetime ReportFromDate = D'2022.01.01'; //期間開始日 input datetime ReportToDate = D'2023.01.01'; //期間終了日 |
それぞれの単語の説明は以下になります。
要素 | 単語 | 説明 |
変数 | input | パラメーターとして変更可能にする為に必要 |
変数 | ReportFromDate | 期間開始日を記録する変数 |
変数 | ReportToDate | 期間終了日を記録する変数 |
値 | D’2022.01.01′ | D’年月日’で記述 |
オリジナル関数の事前準備
今回のコードで使用するオリジナル関数は通貨ペアの価格の精度(小数点以下の桁数)を取得する関数です。
損益pointをPipsに変換する際に必要になります。
1 2 3 4 5 6 7 8 9 10 11 |
//ポジション調整 double AdjustPoint(string Currency){ int SymbolDigits=(int)MarketInfo(Currency,MODE_DIGITS); switch(SymbolDigits){ case 2: return(0.01); break; case 3: return(0.01); break; case 4: return(0.0001); break; case 5: return(0.0001); break; } return(0.0); } |
AdjustPoint()関数に通貨ペアの情報を渡し、MarketInfo()関数で小数点以下の桁数を取得します。
switch処理で該当の値を取得します。
要素 | 単語 | 説明 |
オリジナル関数 | AdjustPoint() | pointとPipsの相互に変換する為の値を取得する関数 |
変数 | Currency | 渡された通貨ペアを保存 |
変数 | SymbolDigits | 通貨ペアの小数点以下の桁数を保存 |
関数 | MarketInfo() | 「気配値表示」ウインドウに表示されている様々な情報を取得 |
プロパティ | MODE_DIGITS | 通貨ペアの小数点以下の桁数 |
処理 | return | ()内の値をAdjuctPoint()関数の戻り値として返す |
処理 | break | switch,while,do while,forのループ処理から抜ける |
OnStart()内のコード作成
メインとなるコードはOnStart()内に記述します。
取引履歴の数を確認
1 2 3 4 5 6 |
int historyTotal = OrdersHistoryTotal(); //決済済み注文の数を取得 if(historyTotal <= 0){ Print("決済済みの注文がありません"); return; } |
OrdersHistoryTotal()関数で決済済み注文の数を取得できます。
その数が0以下の時にPrint()関数で通知して、returnで処理を終了させます。
要素 | 単語 | 説明 |
変数 | historyTotal | 決済済み注文数を記録する変数 |
関数 | OrdersHistoryTotal() | 決済済み注文数を取得 |
関数 | Print() | エキスパートログに表示 |
処理 | return | 関数の実行を終了 |
CSV出力ファイルの名前を作成
1 2 3 4 5 6 7 |
//csv出力ファイル名前を定義 TradingHistoryCSV_YYYYMMDD_HHMM.csv string fileName = "TradingHistoryCSV_"; fileName += string(Year()); fileName += IntegerToString(Month(),2,'0'); fileName += IntegerToString(Day(),2,'0') + "_"; fileName += IntegerToString(Hour(),2,'0'); fileName += IntegerToString(Minute(),2,'0') + ".csv"; |
CSV出力ファイルの名前をfileName変数に+=で連結させて作成します。
最後に”.csv”を連結させるのを忘れないように!
要素 | 単語 | 説明 |
変数 | fileName | CSVファイル名を記録する変数 |
関数 | Year() | 最後に受信したサーバー時間の年を取得 |
関数 | Day() | 最後に受信したサーバー時間の日を取得 |
関数 | Hour() | 最後に受信したサーバー時間の時を取得 |
関数 | Minute() | 最後に受信したサーバー時間の分を取得 |
関数 | IntegerToString() | int型のデータを文字列に変換 |
CSVファイルを作成
1 2 3 4 5 6 7 |
int fDelete = FileDelete(fileName,0); //同じ名前のファイルを消す int fFile = FileOpen(fileName,FILE_CSV | FILE_READ | FILE_WRITE,","); //ファイルを作る if(fFile == INVALID_HANDLE){ Print("CSV出力ファイル作成エラー!!"); return; } |
今回では同じ名前で作成される事はそうないですが、テンプレとして削除して新規作成します。
FileOpen()関数で作成に失敗したらINVALID_HANDLE定数が返ってくるので、失敗した場合にPrint()関数で通知して、returnで処理を終了させます。
要素 | 単語 | 説明 |
変数 | fDelete | FileDelete関数の戻り値を保存 |
関数 | FileDelete() | 指定したファイルを削除 |
変数 | fFile | FileOpen関数の戻り値を保存 |
関数 | FileOpen() | 指定したフラグでファイルを作成・開く |
定数 | INVALID_HANDLE | 無効なハンドル |
ヘッダーを作成
1 2 3 |
//ヘッダーを作成 string header = "チケット,注文タイプ,通貨ペア,ロット,注文時間,注文価格,決済時間,決済価格,損益pips,手数料,スワップ,損益,合計損益,マジックナンバー,コメント" + "\n"; FileWriteString(fFile,header); //1行目のヘッダーに書き込む |
横に長くてすみません。
header変数に,(カンマ)で文字を区切って保存します。
※最後に“\n”を追加する事で改行が行われます。
それをFileWriteString()関数を使ってCSVファイルに書き込みます。
要素 | 単語 | 説明 |
変数 | header | ヘッダー名を保存 |
関数 | FileWriteString() | 文字列データを書き込む |
決済済み注文を検索して書き込む
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
//決済済み注文を検索して書き込む for(int i=0; i<historyTotal; i++){ if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))continue; //決済済み注文データを確認 string history = NULL; //空の文字列でリセット datetime closeTime = OrderCloseTime(); //決済時間を取得 if(ReportFromDate<=closeTime && closeTime<=ReportToDate){ //指定の期間の決済済み注文か確認 history = (string)OrderTicket() + ","; //チケット番号 history += (OrderType() == OP_BUY ? "BUY" : "SELL") + ","; //注文タイプ history += OrderSymbol() + ","; //通貨ペア history += (string)OrderLots() + ","; //ロット数 history += (string)OrderOpenTime() + ","; //注文時間 history += (string)OrderOpenPrice() + ","; //注文価格 history += (string)OrderCloseTime() + ","; //決済時間 history += (string)OrderClosePrice() + ","; //決済価格 double takePrice=0.0; switch(OrderType()){ //損益Pips case OP_BUY: takePrice = (OrderClosePrice() - OrderOpenPrice())/AdjustPoint(OrderSymbol()); break; case OP_SELL: takePrice = (OrderOpenPrice() - OrderClosePrice())/AdjustPoint(OrderSymbol()); break; } history += (string)(NormalizeDouble(takePrice,1)) + ","; //損益Pips history += (string)OrderCommission() + ","; //手数料 history += (string)OrderSwap() + ","; //スワップ history += (string)OrderProfit() + ","; //損益 history += (string)(OrderCommission() + OrderSwap() + OrderProfit()) + ","; //合計損益 history += (string)OrderMagicNumber() + ","; //マジックナンバー history += OrderComment() + "\n"; //コメント FileWriteString(fFile,history); //損益を書き込む } } |
for文を使って決済済み注文数を検索します。
まず初めにOrderSelect()で決済済み注文を確認しますが、失敗した時にはfalseが返されるのでそれを!OrderSelect()と「!」を付ける事で結果が反転します。
つまり失敗した時はfalse→tureに代わるので、if文の条件を満たしcontinue処理されて、for文のループ処理の始めに戻ります。
要素 | 単語 | 説明 |
関数 | OrderSelect() | 注文データを選択 |
処理 | continue | while,do while,forのループ処理の始めに戻る |
変数 | history | CSVに書き込むデータ保存用 |
定数 | NULL | 空の定数 |
変数 | closeTime | 注文の決済時間を保存 |
関数 | OrderCloseTime() | 注文の決済時間を取得 |
次に取得した決済時間が指定期間の決済済み注文か確認して期間内であれば中の処理へ移ります。
history変数にデータを+=と+で連結させながら入れていきますが間に,(カンマ)入れる事を忘れないようにして下さい。
各関数を使用して取得したデータを連結していくだけですが、加工が必要な所を説明します。
<注文タイプ>条件演算子(?と:)を使います。
始めの条件式に合致すれば「?」の後の値を代入し、合致しなければ「:」の後の値を代入します。
つまり、注文タイプがOP_BUYだった場合は“BUY”を代入し、違う場合は“SELL”を代入します。
<損益Pips>注文タイプによって計算式が異なりますので、switch処理を使います。
switch処理でBUYかSELLか判定して、エントリー価格と決済価格の差を求め、AdjustPoint()の値を割って求めて、それをtakePrice変数に代入します。
break処理でswitch処理から抜けるのを忘れないようにして下さい。
最後に連結したデータをCSVへ書き込みます。
要素 | 単語 | 説明 |
関数 | OrderTicket() | 注文のチケット番号を取得 |
関数 | OrderType() | 注文の注文タイプを取得 |
プロパティ | OP_BUY | 買いの成行注文 |
プロパティ | OP_SELL | 売りの成行注文 |
関数 | OrderSymbol() | 注文の通貨ペア名を取得 |
関数 | OrderLots() | 注文のロット数を取得 |
関数 | OrderOpenTime() | 注文の注文時間を取得 |
関数 | OrderOpenPrice() | 注文の注文価格を取得 |
関数 | OrderCloseTime() | 注文の決済時間を取得 |
関数 | OrderClosePrice() | 注文の決済価格を取得 |
変数 | takePrcie | 損益Pipsの保存用 |
処理 | break | switch,while,do while,forのループ処理から抜ける |
関数 | NormalizeDouble() | 小数点以下を指定した桁数で丸めます |
関数 | OrderCommission() | 注文の手数料を取得 |
関数 | OrderSwap() | 注文のスワップを取得 |
関数 | OrderProfit() | 注文の損益を取得 |
関数 | OrderMagicNumber() | 注文のマジックナンバーを取得 |
関数 | OrderComment() | 注文のコメントを取得 |
CSVファイルを閉じる
1 2 |
FileClose(fFile); //ファイルを閉じる MessageBox("CSV出力が完了しました!"); |
for文の処理が終わり抜けた後、最後はCSVファイルを閉じます。
※これは必ず忘れない事!閉じ忘れると開いたMT4以外で対象ファイルが操作出来なくなります。
MassegeBox()で通知を行います。Print関数よりこっちの方が処理が完了した事を視覚で確認が出来る為です。
ファイルの保存場所
CSVファイルは、MT4メニューの「データフォルダを開く」→「MQL4」→「Files」フォルダへ保存されます。
全ソースコード
以下の記事をご購入頂きましたら今回の全ソースコードをまとめて閲覧する事が出来ます。
尚、この記事のコードを模写して行けば同じ物が出来ますので、時短を考える方、この記事を評価して頂ける方だけご購入をご検討下さい( ゚Д゚)
コメント