MetaTrader4の受信TickデータをMySQLに逐次記録するスクリプト作った

完全な趣味ネタですが、為替をコンピュータで分析処理させて売買する投資システムを開発して遊んでいます。
チャートソフトウェアとして秀逸なMetaTrader4(MT4)を主に利用して、EA(自動売買ロジック)を開発するのですが、やはりその環境だけでは分析処理でできることに限界があり。

そこで、MT4の外部でも為替相場の分析するシステムを組んで連携できるようにするために、まずはティックデータをDB化する仕組みを構築しました。
分足・時間足や日足でも良かったのですが、Tickデータがあればそれたの足データは生成できるかなあと思ったので、原データのTickのみを記録対象としています。

以下のソースをyanoshin_tick_export_MySQL.mq4 とファイル名を付けて、experts/indicatorフォルダにコピーします。
その他に、MySQLにC言語から接続するためにlibmysql.dllが必要です。Googleなどでググって、最新版を入手してexperts/librariesフォルダにコピーしておいてください。

お手元に利用できるMySQLサーバを用意してください。データベースを作成し権限のあるユーザを用意したら、以下のソース中のiniti()関数内にあるDB設定の箇所を書き換えてください。

なお、テーブルは作成しなくても、存在しなければ自動的に作成する仕組みにしています。テーブルは通貨ペア毎に作成する仕様で、Ticks_(通貨ペア英字6桁) となります。

コンパイルしたら、MT4の画面上のナビゲーターからindicator>yanoshin_tick_export_MySQLを選択し、チャート画面に適用すると、処理が始まりMySQLにデータをインポートします。 なお外部のlibmysql.dllからMySQLへ接続する処理があるため、インジゲーターを適用する際、「Allow DLL imports」にチェックをいれて許可してあげてください。

*ひとまず解説はここまでですが、リクエストがあれば詳細あとで書きます。ほとんどはソースを読んでいただけると、何がやりたいかなどは読み取れると思いますが。

#property copyright “copyright Yanoshin”
#property link “http://yanoshin.jp”

//indicator setting
#property indicator_chart_window

//MySQL setting
#import “libmysql.dll”
int mysql_init(int db);
int mysql_errno(int TMYSQL);
int mysql_real_connect( int TMYSQL,string host,string user,string password, string DB,int port,int socket,int clientflag);
int mysql_real_query(int TMSQL,string query,int length);
void mysql_close(int TMSQL);
int mysql;

//SQL Log file setting
int handle;

//variables setting
datetime now_dt;
string now_str;
string symbol;
string table_name;
string chkDate;
string chkDate2;

//Initiation
int init()? {
symbol = Symbol();

//make SQL Logfile at first
//SQL logfile is supporsed to be used as a backup
chkDate = TimeDay(now_dt);
handle = makeNewFile();

//—- MySQL setup
mysql=mysql_init(mysql);
if (mysql!=0) Print(“MySQL allocated”);//Log

string host=”host.of.mysql.db”;
string user=”_username_”;
string password=”_password_”;
string DB=”_dbname_”;
int clientflag=0;
int port=3306;
string socket=””;
int res=mysql_real_connect(mysql,host,user,password,DB,port,socket,clientflag);
int err=GetLastError();
if (res==mysql) Print(“MySQL connected”);
else {
Print(“error=”,mysql,” “,mysql_errno(mysql),” “);
return(1);
}

//Check the existance of DB table.
//if not, build a table named with Symbol()
table_name = “Ticks_”+symbol;
string query=””;
query = query + “CREATE TABLE IF NOT EXISTS “+table_name+” (“;
query = query + “id bigint unsigned NOT NULL auto_increment,”;
query = query + “symbol varchar(10) NOT NULL,”;
query = query + “datetime datetime NOT NULL,”;
query = query + “utime int unsigned NOT NULL,”;
query = query + “close float NOT NULL,”;
query = query + “ask float NOT NULL,”;
query = query + “bid float NOT NULL,”;
query = query + “volume_in_M1 int unsigned NOT NULL,”;
query = query + “broker char(50) NOT NULL,”;
query = query + “src_terminal varchar(50) NOT NULL,”;
query = query + “PRIMARY KEY? (id)”;
query = query + “) ENGINE=MyISAM? DEFAULT CHARSET=utf8;”;
int length=0;
length=StringLen(query);
mysql_real_query(mysql,query,length);
int myerr=mysql_errno(mysql);
if (myerr>0)Print(“error=”,myerr);

return(0);
}

//Main procedure
int start() {
//LogFile chake
chkDate2 = TimeDay(now_dt);
if(chkDate != chkDate2)? {
//if datetime changed since privious, make a new logfile
closeFile(handle);
handle = makeNewFile();
chkDate = chkDate2;
}

//get a datetime data.
now_dt = TimeCurrent();
now_str = TimeToStr(now_dt, TIME_DATE|TIME_SECONDS);

//
int limit = Bars – IndicatorCounted();
//Print(“Sumbol=”, symbol, “NOW = “,now_str ,”Datetime = “, now_dt, ” Close[0]=”,Close[0], ” Bid=”,Bid, ” Ask=”,Ask);//DEBUG

if(limit == 1) {
//—- SQL query setup
string query=””;
query = query + “insert into “+table_name+” (“;
query = query + “symbol, datetime, utime, close, ask, bid, volume_in_M1, broker, src_terminal”;
query = query + “) values(“;
query = query + “\””+Symbol()+”\”,”;
query = query + “\””+TimeToStr(CurTime(),TIME_DATE|TIME_SECONDS)+”\”,”;
query = query + now_dt+”,”;
query = query + NormalizeDouble(Close[0],6)+”,”;
query = query + Ask+”,”;
query = query + Bid+”,”;
query = query + iVolume(Symbol(),PERIOD_M1,0)+”,”;
query = query + “\”MetaTrader4\”,”;
query = query + “\”VM-Win-Trade\””;
query = query + “);”;
//Print(query);

//output SQL backup into Logfile
FileSeek(handle, 0, SEEK_END);
FileWrite(handle, query);

//—- MySQL writing
int length=0;
length=StringLen(query);
mysql_real_query(mysql,query,length);
int myerr=mysql_errno(mysql);
if (myerr>0)Print(“error=”,myerr);

}
return (0);

}

int deinit()? {
closeFile(handle);
}

int makeNewFile() {
now_dt = TimeCurrent();
now_str = TimeToStr(now_dt, TIME_DATE|TIME_SECONDS);

int handle;

string dirpath = “MySQL_log\\” + “”+TimeYear(now_dt)+”-“+TimeMonth(now_dt)+”-“+TimeDay(now_dt);
string filename = dirpath+ “\\” + symbol + “_Tick.sql”;
handle = FileOpen(filename, FILE_CSV | FILE_READ | FILE_WRITE,? ‘,’);

string msg = “– ——-Session opened[“+now_str+”]——-“;
FileSeek(handle, 0, SEEK_END);
FileWrite(handle, msg);
return(handle);

}

int closeFile(int handle){
now_dt = TimeCurrent();
now_str = TimeToStr(now_dt, TIME_DATE|TIME_SECONDS);
string msg = “– ——-Session closed[“+now_str+”]——-“;
FileSeek(handle, 0, SEEK_END);
FileWrite(handle, msg);
FileClose(handle);
}

シェアする

  • このエントリーをはてなブックマークに追加

フォローする

コメント

  1. はじめまして より:

    ティックをWEBにリアルタイムに近い形で表示したいのですが
    可能でしょうか?
    私には知識が足りなく、IT業者にも断られてます。
    探し探してこの記事に辿り着きました。
    制作依頼になってしまい申し訳ございませんが
    お時間ありましたら上記アドレスにご連絡いただけると幸いです。

    • yanoshin より:

      どうも。リアルタイムに近い形、ということで最大で20秒くらいの遅延を許すくらいのティックチャートなら自作でも開発できそうな気がします。

      ただ、もし数秒以下という遅延許容ということになるとMT4を使用する時点でかなり難しい要件かなという印象があります。
      というのも、接続する業者次第ですがMT4に配信されたティックデータの時点で実際にはかなり遅延している可能性があり、さらにそこから
      ・データベースへの逐次インサート(挿入)処理
      ・表示側WEBブラウザからの定期的リクエスト(秒単位)
      ・WEBサーバがDBから取得したティックデータをブラウザに返すまでのレスポンスタイム
      ・また上記に掛かるネットワーク通信での遅延
      ・ブラウザ上でティックグラフを描画する処理
      という主な処理が必要となると想定するだけでもそれぞれ数秒ずつが積み重なり、十数秒くらいかなあという目算でした。

      もちろん、これらのシステム設計と開発方法を究極まで工夫することで、リアルタイムと言えるくらいの速いティック表示も開発可能だと思いますが、その場合に必要なリソースやコストなども跳ね上がってしまうかと思います。

      もし、上記の回答で実際にご要望があれば、費用・期間などご相談いつでも可能ですのでご一報いただけると幸いです。