MT4で定期的に取引記録のCSVを自動エクスポートするプログラム

CSV自動ダウンロード

この記事で紹介しましたが、EAでFXを全自動化する実験をおこなっています。

折角なら取引記録の確認も自動で行えるようにしたい、という思いからこのブログへの取引記録自動投稿プログラムをPythonで組みました。

取引記録の自動投稿

今回はこの①毎週12時に取引記録をCSVで保存するプログラムについて解説します。

かなりネットサーフィンしましたが、「csv_Report.mq4」や「TFF-Report2」、「ExportCsvTradeHistory_Sc」などは、CSVでダウンロードできるものの、モノがスクリプトであるため毎回VPSにログインしてMT4を起動してCSVをダウンロードする必要があるものばかりでした。

全自動化したいのにこれでは非効率です。(公開している皆さんスミマセン)

自分は極度の面倒くさがり屋なので、毎週指定した時間に自動的にCSVがダウンロードされるEAができたらいいなあ~と思っていましたが、結局そのようなものは見つからず、自分で作ることになりました。

CSVの自動ダウンロードをスケジュールで実行する、って需要ありそうなのに意外にないもんなんですね?もしくは作るけど公開していないだけ?

まだ実装して数日しか経っていないので、バグがなければこの記事に公開する予定です。

MQL4初心者だったので、CSV出力についてはこのブログを参考にしました。

あとは恥ずかしながらC系言語も触ったことがないので、文法の慣習とかよく分かりませんのでご了承下さい。

では早速いってみましょう。

具体的なコード

まずはパラメータの設定です。グローバル変数部分に以下の記述をします。

 

//パラメータ設定
input int SetWeek = 0;
input int SetHour = 12;
input int SetMin = 0;

 

SetWeekには「0~6」の数字を入れます。0が日曜日で、6が土曜日です。SetHourには自動でCSVをエクスポートさせたい時間、SetMinは分です。

これらの数字は、TimeLocal()との条件式で使用するため、MT4のサーバー時刻ではなくお使いのパソコンの時刻を設定するようにお願いします。

このコードであれば、日曜日のお昼12時に自動でMQL4 > Filesに保存されます。

次はOnTimer()を使うための慣習的な記載?をします。

 

int OnInit()
  {
   EventSetTimer(60);
   return(INIT_SUCCEEDED);
  }  

void OnDeinit(const int reason)
  {
//---
   EventKillTimer();
  }

 

正直なぜこれを記載すればいいのか分かりませんが、OnTimer()を使う場合はこう記載せよとのことでした。

EventSetTimer(60)は、何秒ごとにイベントを発生させるかという命令なので、例えば1秒ごとに発生させたいという場合は、EventSetTimer(1)という記述になります。

今回はパラメータが分単位までしか設定できない仕様にしているため、60秒に1度実行する設定にしています。1秒ごとにイベント発生してたらPCに負荷掛かるのかな?

次はOnTimer()内での、変数宣言です。

 

void OnTimer(){

   //準備
   int fileHandle = -1;
   int i;
   int hstTotal = OrdersHistoryTotal();
   datetime openTime;
   datetime closeTime;
   
   //時間の宣言
   int YEAR = TimeYear(TimeLocal());
   int MONINT = TimeMonth(TimeLocal());
   int DAYINT = TimeDay(TimeLocal());
   int WEEK = TimeDayOfWeek(TimeLocal());
   int HOUR = TimeHour(TimeLocal());
   int MIN = TimeMinute(TimeLocal());
   int SEC = TimeSeconds(TimeLocal());
   
   string MON = (string)StringToInteger(MONINT);
   string DAY = (string)StringToInteger(DAYINT);
   
   if(MONINT < 10) MON = StringConcatenate("0",MONINT);
   if(DAYINT < 10) DAY = StringConcatenate("0",DAYINT); 

特に解説する必要はない気がしますが、上述の通り基本的にはTimeLocal()で記載をしているので、使っているパソコンの時刻を基準としてこのプログラムは動きます。

またCSVの形式を「Balance_YYYYMMDD.csv」としたかったため、

もし月や日が10より小さい場合、String形式で「0X」となるようにしています。

例えば2020年1月1日の場合は20200101という風になります。

続いてint hstTotal = OrdersHistoryTotal();で取得したヒストリカルデータの有無を確認する処理になります。OnTimer()内に記述します。

 

   //ヒストリカルデータがある時の処理
   if( hstTotal > 0 && WEEK==SetWeek && HOUR==SetHour && MIN==SetMin){
      string fileName = StringConcatenate("Balance_",YEAR,MON,DAY,".csv");
      fileHandle = FileOpen(fileName, FILE_CSV|FILE_WRITE, ",");
      Comment("最終CSV出力時間:"+YEAR+"年"+MONINT+"月"+DAYINT+"日"+HOUR+"時"+MIN+"分");
   }

   //ヒストリカルデータがない時の処理
   if( hstTotal <= 0 ){
      Comment("ヒストリカルデータがありませんでした:"+YEAR+"年"+MONINT+"月"+DAYINT+"日"+HOUR+"時"+MIN+"分");
      return;
   }

 

ヒストリカルデータがあり、且つ前段のパラメータ設定のSetWeek、SetHour、SetMinが、LocalTime()で取得したWEEK、HOUR、MINと一致した時にCSVファイルを開く指示をしています。

無事、開くことができたらチャート内にコメントがでるような仕様になっております。

一方でヒストリカルデータがなかった場合も、チャート内にコメントがでるようになっております。

続いてヘッダ・CSVの出力です。

 

   // ヘッダ出力
   FileWrite(fileHandle,
      "Balance",
      "Number",
      "EntryDate",
      "ProfitDate",
      "Swap",
      "Commission",
      "Profit");
      
   for(i=0;i<hstTotal;i++)
   {
      // 決済したものでBUYとSELLのみ対象
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true){
         if(OrderType() == OP_BUY || OrderType() == OP_SELL){
            openTime = OrderOpenTime();
            closeTime = OrderCloseTime();

            // ファイル末尾へポインタ変更
            FileSeek(fileHandle, 0, SEEK_END);

            // 日付形式をYY.MM.DD→YY/MM/DDへ変換
            string strOpenTime = TimeToStr(openTime);
            string strCloseTime = TimeToStr(closeTime);
            StringReplace( strOpenTime,".","/");
            StringReplace( strCloseTime,".","/");

            // CSV1件出力   
            FileWrite(fileHandle,
                     AccountBalance(),
                     OrderTicket(),
                     strOpenTime,
                     strCloseTime,
                     OrderSwap(),
                     OrderCommission(),
                     OrderProfit()
            );
         }
      }
   }
   
   FileClose(fileHandle);
  }

 

このあたりは完全にこのブログからコピペしました。分かりやすかったです。ありがとうございます。

変えた部分としてはAccountBalance()を入れたことで、現在の口座残高も取得できるようにしました。

CSVの出力結果は例えば10回取引されていても、10回とも同じ数字がBalance列に入りますw

これは完全に記事の自動投稿用なので、不要の方はAccoutBalance()と、ヘッダーの“Balance”を削除してください。

プログラムのダウンロード

バグ・修正を行い次第公開予定です。

非エンジニアでもMQL4でプログラムを作成できたので、これを読めば知見がない人でも作成できると思います。