
MetaTrader 4 クライアントターミナルと MS SQL Server の統合
はじめに
別の製品との統合を行うことで、トレーディングにおいて付加的な挑戦が可能となります。
それには多くの用途があるので、以下にそのうちのいくつかを提示します。
ティックを収集し、それをさらに分析するため MS SQL SERVER に渡します。大きなティック履歴を取得することで、最小の時間単位から開始し非標準的な期間まで任意の期間を収集することができます。実ティックのクオートを取得することで、「スキャルパ」として知られるティックデータ依存の戦略をデバッグすることができます。
別アプリケーションから取り入れられたデータを素早く分析するためにストアをしようすることができます。たとえば、マイクロソフトエクセルや別の第三者ソフトウェア、または自分自身のプロダクトからのデータです。
たとえば、ターミナルの「ヒストリーセンター」から MS SQL に全履歴をアンロードすることが可能です。そして MT4 にその履歴を格納する必要はありません。これはターミナルメモリへの負荷を軽減するのに役立ちます。
MS SQL SERVER に格納されたクオートを利用してニューラルネットワークを計算することができます。たとえば、ネットワーク信号を MT4 に渡すことでリアルタイムモードで STATISTICA - 7.8 により SQL からクオートをダウンロードすることができるのです。
別言語で別シンボルに対する独自のプログラムを作成することができ、サーバーを使ってシグナルを渡すことができます。あとはクライアントターミナルに対する関数を実行するだけで、重い計算の負荷を軽減できるのです。
本プロジェクトには以下のソフトウェア製品が使用されました。
- MS SQL SERVER 2000 Developer - BASE
- VISUAL C++ 6.0 SP5 -DLL "YZMSSQLExpertSample.dll" を作成するため
- MDAC 7
インストールするのは最小セットです。
1 MS SQL SERVER 2000 Developer
2 MDAC 7
私は MDAC によってプログラムをデバッグしました。ただし、古いバージョンの一部ですべて正常に動作する可能性があります。DLL をコンパイルするつもりがなければ、Visual C++ 6.0 をインストールする必要や、インストール済みを取得する必要はありません。既製の DLL を使用することができます。ですが、私はそこにユーザー名、DSN 名、接続をハード配線しました。みなさんは自分バージョンのプログラムに上記リストアップされたものをすべて繰り返す必要があります。ここでMS SQL SERVER や Visual C++ 6.0のインストール方法を説明しません。そういった事柄はこの特定の記事の範囲外であります。
必要なソフトウェア製品がインストールされたら、DSN を作成します。
dsn=MT4_SQL_BASE;", "yuraz", "qwerty"
MS SQL でのティック受け取り例
実験はすべて MS SQL SERVER 2000 Developer によって行われました。Visual C++ 6.0 では、ADO を介して MS SQL にアクセスする方法で YZMSSQLExpertSample.DLL が作成されました。MDAC 7 または MDAC 8 をインストールする必要があります。プロシージャおよびテーブルの作成方法例についてのみ説明します。MS SQL で作成するものの最小セットはべース、テーブル、プロシージャです。ティッククオートを処理するテーブルとプロシージャを考察します。ご希望なら他に関数を追加することも可能です。
ベースとテーブルは MS SQL で作成する必要があります。私は MT4TRADE という名前で新しいベースを作成しました。そしてその中にテーブルを作成します。
MT4TICK -ティックテーブル
//----------------------------------------------------------------------------------- // // Structure of MT4TICK Base // // idc - formed automatically, unique number of record // ServerDateTime - Filled out automatically, when adding a record // Server local time - time when the quote was placed in the table // (it doesn't have anything in common with the date and time passed by MT4) // it is the time counted by the server itself - it will be the same as the time // of the machine, on which the server has been launched. //--- // iDateTime - date and time in MT4 format, passed from MT4 // sSymbol - symbol // cAsk - quote Ask // cBid - quote Bid // CREATE TABLE [dbo].[MT4TICK] ( [idc] [bigint] IDENTITY (1, 1) NOT NULL , [ServerDateTime] [datetime] NULL , [iDateTime] [bigint] NULL , [sSymbol] [char] (6) COLLATE SQL_Latin1_General_CP1251_CI_AS NULL , [cAsk] [numeric](18, 4) NULL , [cBid] [numeric](18, 4) NULL ) ON [PRIMARY] GO --- Include automated filling out the ServerDateTime field with the date and time of server MS SQL ALTER TABLE [dbo].[MT4TICK] ADD CONSTRAINT [DF_MT4TICK_ServerDateTime] DEFAULT (getdate()) FOR [ServerDateTime] GO
以下は表示されるプロシージャをティックが受け取り表にする方法です。
// // @RetCode int out --- used for returning // ,@psSymbol char(6) --- symbol // ,@piDateTime bigint --- date and time of tick arrival // ,@pdAsk float --- Ask // ,@pdBid float --- Bid // // The procedure just returns 0 // if we analyze the code of returning to MQL4, we can see that the quote has reached the procedure and has been tabulated // // CREATE PROCEDURE dbo.YZ_MT4_TICK @RetCode int out ,@psSymbol char(6) ,@piDateTime bigint ,@pdAsk float ,@pdBid float AS insert into MT4TICK ( sSymbol, iDateTime, cAsk, cBid ) values ( @psSymbol , @piDateTime, @pdAsk , @pdBid ) select @RetCode=0 return @RetCode
上記説明から、どの目的にためにどの手順が使用されるかわかります。
@RetCode -DLL から渡されるときは何も機能を持ちません。ターミナルコードを受け取る役目を果たすだけです。
MS SQL SERVER の設定が終わりました。標準的なコンフィギュレーションを作成するスクリプトは本稿に添付されています。
想像しましょう。可能なソリューション、そしてプラスα
データストレージを作成し、そこに情報を出し入れします。このように、MT 4 クライアントターミナルをクオート履歴を格納する必要性から解放します。次に、クオート履歴はに格納され、この情報で作業し、すぐにそれを抽出し、別のアプリケーションにエクスポートすることができます。NEURAL パッケージで分析するデータを使用することができます。そのほとんどは SQL ストレージと連携可能です。
リアルタイムでターミナルはインディケータからのシグナルを形成し、ストレージに私、この方法で修正し続けます。外部アプリケーションはシグナルと履歴をリアルタイムで抽出し、分析し、実行との MS SQL Server ストレージを修正しながらシグナルを形成し、実行するためにターミナルへ送信します。
このように、自動化されたトレーディング複合体に関与するアプリケーション間での統合と機能分配ができるです。
履歴クオートを格納する必要がもうなければ、それを以下のように設定します。最小バー、たとえば5000を Tools → Options → Chartsで設定します。ターミナルはより速く動作し始めます。というのも、大きな履歴についてのメモリを割り当てる必要がないためです。
ソーステキスト
DLL コード
//+------------------------------------------------------------------+ //| Sample DLL for MQL4 | //| Copyright c 2004-2008, MetaQuotes Software Corp. | //| https://www.metaquotes.net | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ // // YURAZ 2008 YZMSSQLExpertSample // // Example DLL Integrating MT4 with MS SQL 2000 // // ADO MS SQL SERVER // // software used // // VISUAL C++ 6 , SP5 , MDAC 7 , MS SQL2000 + SP4 // //+------------------------------------------------------------------+ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include <windows.h> #include <stdlib.h> #include <stdio.h> //---- #define MT4_EXPFUNC __declspec(dllexport) //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ #pragma pack(push,1) struct RateInfo { unsigned int ctm; double open; double low; double high; double close; double vol; double vol1; double vol2; double vol3; double vol4; double vol5; }; #pragma pack(pop) struct MqlStr { int len; char *string; }; static int CompareMqlStr(const void *left,const void *right); static int SQLexecProcedure( char *nprc ); static int SQLexecProcedureSignal( char *sSymbol, char* sProcedure ); // static int _YZSQLsqlstrinsql( char *Symbol , unsigned int DateTime , double Ask, double Bid, char *NamePrc ); static int _YZSQLprocedure ( char *sSymbol, unsigned int pDateTime, double Ask, double Bid, char *NamePrc ); static int _YZSQLprocedureHISTORYPut(char *Symbol,unsigned int Period, unsigned int DateTime,double Open, double High,double Low, double Close ,double Volume, unsigned int Bar ,char *Procedure); //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ BOOL APIENTRY DllMain(HANDLE hModule,DWORD ul_reason_for_call,LPVOID lpReserved) { //---- switch(ul_reason_for_call) { case DLL_PROCESS_ATTACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } //---- return(TRUE); } // place ticks in MS SQL // call the procedure as an SQL line passing parameters "exec YZ_MT4_TICK ?,?,?,?" /* MT4_EXPFUNC int __stdcall SQLsqlstringTickPut(char *Symbol,unsigned int DateTime,double Ask,double Bid,char *sSQLstring) { int ccc = _YZSQLsqlstrinsql( Symbol , DateTime , Ask , Bid , sSQLstring ); return(ccc); } */ // call as a procedure passing parameters MT4_EXPFUNC int __stdcall SQLProcedureTickPut(char *Symbol,unsigned int DateTime,double Ask,double Bid,char *Procedure) { int ccc = _YZSQLprocedure( Symbol , DateTime , Ask , Bid ,Procedure ); return(ccc); } // place a specific candlestick in MS SQL history MT4_EXPFUNC int __stdcall SQLProcedureHistoryPut(char *Symbol,unsigned int Period , unsigned int DateTime, double Open,double High,double Low, double Close ,double Volume,unsigned int Bar ,char *Procedure) { int ccc = _YZSQLprocedureHISTORYPut(Symbol,Period,DateTime,Open,High,Low,Close,Volume,Bar,Procedure); return(ccc); } // call procedure sProcedure // // return -1 error // MT4_EXPFUNC int __stdcall SQLProcedureGetInt(char *sProcedure) { int Ret = SQLexecProcedure( sProcedure ); return((int)Ret); } MT4_EXPFUNC int __stdcall SQLProcedureGetSignal (char *sSymbol, char *sProcedure) { int Ret = SQLexecProcedureSignal( sSymbol, sProcedure ); return((int)Ret); } ////////////////////////////////// #include "stdafx.h" #include <stdio.h> #import "C:\Program Files\Common Files\System\ado\msado20.tlb" \ rename("EOF","ADOEOF") rename("BOF","ADOBOF") using namespace ADODB; inline void TESTHR(HRESULT x) { if FAILED(x) _com_issue_error(x); }; // procedure call method int _YZSQLprocedure( char *sSymbol, unsigned int pDateTime, double Ask, double Bid, char *NamePrc ) { HRESULT hr = S_OK; _CommandPtr pCmd = NULL; _ConnectionPtr pConnection = NULL; _bstr_t strMessage, strAuthorID; ::CoInitialize(NULL); long codRet = -1; try { _ParameterPtr Par1; _ParameterPtr Par2; _ParameterPtr Par3; _ParameterPtr Par4; _ParameterPtr Par5; TESTHR(pConnection.CreateInstance(__uuidof(Connection))); hr = pConnection->Open("dsn=MT4_SQL_BASE;", "yuraz", "qwerty", adConnectUnspecified); pConnection->CursorLocation = adUseClient; TESTHR(pCmd.CreateInstance(__uuidof(Command))); pCmd->CommandText = NamePrc; // procedure name pCmd->CommandType = adCmdStoredProc; Par1 = pCmd->CreateParameter( _bstr_t("@P1"), adInteger, adParamOutput,0, codRet ); pCmd->Parameters->Append( Par1 ); Par1 = pCmd->CreateParameter("@psSymbol",adChar, adParamInput, strlen(sSymbol) ,sSymbol ); pCmd->Parameters->Append(Par1); Par2 = pCmd->CreateParameter("@piDateTime", adDouble , adParamInput, sizeof(double) , (double)pDateTime ); pCmd->Parameters->Append(Par2); Par3 = pCmd->CreateParameter("@pdAsk", adDouble, adParamInput, 4, Ask ); pCmd->Parameters->Append(Par3); Par4 = pCmd->CreateParameter("@pdBid", adDouble, adParamInput, 4, Bid ); pCmd->Parameters->Append(Par4); pCmd->ActiveConnection = pConnection; int hr = pCmd->Execute( 0, 0, adCmdStoredProc ); if( FAILED(hr) ) { codRet = -1; } else { Par1 = pCmd->Parameters->GetItem(_bstr_t("@P1")); // obtain from the procedure codRet = Par1->GetValue(); } } catch(_com_error ) { // // if necessary, process the execution error // codRet = -1; } if (pConnection) if (pConnection->State == adStateOpen) pConnection->Close(); ::CoUninitialize(); return((int)codRet); } // place in history Symbol , Period . DateTime, Open , High , Low , Close , Value , Bar int _YZSQLprocedureHISTORYPut(char *pSymbol,unsigned int pPeriod, unsigned int pDateTime,double pOpen,double pHigh, double pLow, double pClose ,double pVolume, unsigned int pBar ,char *pProcedure ) { HRESULT hr = S_OK; _CommandPtr pCmd = NULL; _ConnectionPtr pConnection = NULL; _bstr_t strMessage, strAuthorID; ::CoInitialize(NULL); long codRet = -1; try { _ParameterPtr ParReturn; // _ParameterPtr Par1; // SYMBOL _ParameterPtr Par2; // PERIOD _ParameterPtr Par3; // DATETIME _ParameterPtr Par4; // OPEN _ParameterPtr Par5; // HIGH _ParameterPtr Par6; // LOW _ParameterPtr Par7; // CLOSE _ParameterPtr Par8; // VOLUME _ParameterPtr Par9; // BAR TESTHR(pConnection.CreateInstance(__uuidof(Connection))); hr = pConnection->Open("dsn=MT4_SQL_BASE;", "yuraz", "qwerty", adConnectUnspecified); pConnection->CursorLocation = adUseClient; TESTHR(pCmd.CreateInstance(__uuidof(Command))); pCmd->CommandText = pProcedure; // procedure name pCmd->CommandType = adCmdStoredProc; ParReturn = pCmd->CreateParameter( _bstr_t("@P1"), adInteger, adParamOutput,0, codRet ); pCmd->Parameters->Append( ParReturn ); Par1 = pCmd->CreateParameter("@psSymbol",adChar, adParamInput, strlen(pSymbol) ,pSymbol ); pCmd->Parameters->Append(Par1); Par2 = pCmd->CreateParameter("@piDateTime", adDouble , adParamInput, sizeof(double) , (double)pPeriod ); pCmd->Parameters->Append(Par2); Par3 = pCmd->CreateParameter("@piDateTime", adDouble , adParamInput, sizeof(double) , (double)pDateTime ); pCmd->Parameters->Append(Par3); Par4 = pCmd->CreateParameter("@pdOpen", adDouble, adParamInput, 4, pOpen ); pCmd->Parameters->Append(Par4); Par5 = pCmd->CreateParameter("@pdHigh", adDouble, adParamInput, 4, pHigh ); pCmd->Parameters->Append(Par5); Par6 = pCmd->CreateParameter("@pdLow", adDouble, adParamInput, 4, pLow ); pCmd->Parameters->Append(Par6); Par7 = pCmd->CreateParameter("@pdClose", adDouble, adParamInput, 4, pClose ); pCmd->Parameters->Append(Par7); Par8 = pCmd->CreateParameter("@pdVolume", adDouble, adParamInput, 4, pVolume ); pCmd->Parameters->Append(Par8); Par9 = pCmd->CreateParameter("@piBar", adDouble , adParamInput, sizeof(double) , (double)pBar ); pCmd->Parameters->Append(Par9); pCmd->ActiveConnection = pConnection; int hr = pCmd->Execute( 0, 0, adCmdStoredProc ); if( FAILED(hr) ) { codRet = -1; } else { ParReturn = pCmd->Parameters->GetItem(_bstr_t("@P1")); // obtain from the procedure codRet = ParReturn->GetValue(); } } catch(_com_error ) { // // if necessary, process the execution error // codRet = -1; } if (pConnection) if (pConnection->State == adStateOpen) pConnection->Close(); ::CoUninitialize(); return((int)codRet); } // // return the value returned by the procedure // int SQLexecProcedure( char *nprc ) { HRESULT hr = S_OK; _CommandPtr pcmd = NULL; _ConnectionPtr pConnection = NULL; _bstr_t strMessage, strAuthorID; ::CoInitialize(NULL); long codRet = -1; try { TESTHR(pConnection.CreateInstance(__uuidof(Connection))); hr = pConnection->Open("dsn=MT4_SQL_BASE;", "yuraz", "qwerty", adConnectUnspecified); pConnection->CursorLocation = adUseClient; TESTHR(pcmd.CreateInstance(__uuidof(Command))); pcmd->CommandText = nprc; // procedure name pcmd->CommandType = adCmdStoredProc; _ParameterPtr pParm1 = pcmd->CreateParameter( _bstr_t("@P1"), adInteger, adParamOutput,0, codRet ); pcmd->Parameters->Append( pParm1 ); pcmd->ActiveConnection = pConnection; int hr = pcmd->Execute( 0, 0, adCmdStoredProc ); if( FAILED(hr) ) { codRet = -1; } else { pParm1 = pcmd->Parameters->GetItem(_bstr_t("@P1")); // obtain from the procedure codRet = pParm1->GetValue(); } } catch(_com_error ) { // // if necessary, process the execution error // codRet = -1; } if (pConnection) if (pConnection->State == adStateOpen) pConnection->Close(); ::CoUninitialize(); return((int)codRet); } // // // int SQLexecProcedureSignal( char *sSymbol, char* sProcedure ) { HRESULT hr = S_OK; _CommandPtr pcmd = NULL; _ConnectionPtr pConnection = NULL; _bstr_t strMessage; _bstr_t strAuthorID; ::CoInitialize(NULL); long codRet = 0; try { TESTHR(pConnection.CreateInstance(__uuidof(Connection))); hr = pConnection->Open("dsn=MT4_SQL_BASE;", "yuraz", "qwerty", adConnectUnspecified); pConnection->CursorLocation = adUseClient; TESTHR(pcmd.CreateInstance(__uuidof(Command))); pcmd->CommandText = sProcedure; // procedure name pcmd->CommandType = adCmdStoredProc; _ParameterPtr pParm1 = pcmd->CreateParameter("@psSymbol",adChar, adParamInput, strlen(sSymbol) ,sSymbol ); pcmd->Parameters->Append(pParm1); _ParameterPtr pParm2 = pcmd->CreateParameter( _bstr_t("@P1"), adInteger, adParamOutput,0, codRet ); pcmd->Parameters->Append( pParm2 ); pcmd->ActiveConnection = pConnection; int hr = pcmd->Execute( 0, 0, adCmdStoredProc ); if( FAILED(hr) ) { bool bSuccess = false; } pParm2 = pcmd->Parameters->GetItem(_bstr_t("@P1")); // obtain from the procedure codRet = pParm2->GetValue(); // printf("\n [%d] \n",codRet ); // OBTAINING from the procedure } catch(_com_error ) { // // if necessary, process the execution error // } if (pConnection) if (pConnection->State == adStateOpen) pConnection->Close(); ::CoUninitialize(); return((int)codRet); }
MQL4 からの呼出し例
// Comments are reduced to make it appear simpler, the comments in the attached files are complete //+------------------------------------------------------------------+ //| | //| Copyright c 1999-2006, MetaQuotes Software Corp. | //| http://www.metaquotes.ru | //| YZMSSQLSample.mq4 | //| Yuriy Zaitsev | //+------------------------------------------------------------------+ // Example of integrating with MS SQL | //+------------------------------------------------------------------+ #property copyright "YURAZ Copyright(C) 2008" #property link "yzy @ mail.ru" //+------------------------------------------------------------------+ // DLL function library //+------------------------------------------------------------------+ #import "YZMSSQLExpertSample.dll" // Performing any actions on MS SQL Server, procedure is called SQLProcedureGetInt // Collecting ticks int SQLProcedureTickPut( string, int , double , double ,string ); int Prc = 0; int init() { // // SQLProcedureGetInt The function, once having called a certain procedure, // will return into MT4 int value, for example, parameters // stored on MS SQL server, formed by another software // Prc = SQLProcedureGetInt ("YZ_MT4_T1"); return(0); } int start() { int a; int RetCode = SQLProcedureTickPut( Symbol(), TimeCurrent() , Ask, Bid ,"YZ_MT4_TICK"); // call to the tick collecting procedure Print(" SQLProcedureTickPut (YZ_MT4_NEWDAY)"+ RetCode ); // Example: // on MS SQL server, you can filter signals formed using third-party software // neural networks // other software products // /* int Signal = SQLProcedureGetSignal (Symbol() , "YZ_MT4_SIGNAL" ); // procedure MS SQL , will return signal Print(" SQLProcedureGetSignal (Symbol() , YZ_MT4_SIGNAL )"+ Signal ); if ( Signal == OP_BUY ) { // the procedure has returned the signal and is recommending to buy } if ( Signal == OP_SELL ) { // the procedure has returned the signal and is recommending to sell } */ return(0); }
MS SQL Server へ履歴をロードするスクリプト
// // YURAZ 2008 yzh @ mail.ru // // script loading history onto MS SQL // reload all history for all currency pairs and for all TIMEFRAMES // in MS SQL // #import "YZMSSQLExpertSample.dll" int SQLProcedureHistoryPut( string, int , int, double , double ,double , double ,double ,int, string ); static int mPeriod[8]={PERIOD_M1,PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1,PERIOD_W1,PERIOD_MN1}; void start() { PutHistor("EURUSD"); PutHistor("USDCHF"); Comment(" LOADING COMPLETE " ); } void PutHistor(string sSymbol) { for ( int iPeriod = 0; iPeriod <= 8 ; iPeriod++ ) { int pPERIOD_XX = mPeriod[iPeriod]; int Bar = iBars(sSymbol,pPERIOD_XX ); // obtain the depth of history for the given timeframe // no progress bar organized for ( int iBar = Bar; iBar >= 0 ; iBar--) { Comment( "WAIT TIMEFRAME "+pPERIOD_XX+" SYMBOL "+sSymbol+" BARS "+iBar ); double o = iOpen (sSymbol,pPERIOD_XX,iBar); double h = iHigh (sSymbol,pPERIOD_XX,iBar); double l = iLow (sSymbol,pPERIOD_XX,iBar); double c = iClose (sSymbol,pPERIOD_XX,iBar); double v = iVolume(sSymbol,pPERIOD_XX,iBar); datetime d = iTime (sSymbol,pPERIOD_XX,iBar); int RetCode = SQLProcedureHistoryPut( sSymbol,pPERIOD_XX,d,o,h,l,c,v,iBar, "YZ_MT4_HISTORY"); // Print ( " YZ_MT4_HITSRY "+RetCode); } } }
注意:残念ながら、スクリプトを使用すると全履歴のロードはかなり遅くなりますが、それは明らかにハイクオリティーでバー数を修正します。
最良のソリューションはクオートをテキストファイルにアンロドし、それを IMPRT EXPORT DTS によって MS SQL にロードすることです。各シンボルについて 1999~2008 の M1 履歴をロードするのにかかるのは数分です。
テキストファイルへアンロードする際、バーインデックスはアンロードされません。バーインデックスをただの行番号とするのであれば、漏れたバーの問題が起こり、変更したり再ロードする場合、アンロードされたバーの番号は MS SQL や MT 4 にあるのと異なる可能性があります。この問題はまだ解決していませんが、MT 4 自体でハイクオリティーな履歴更新後履歴を再ロードすることで解決できると考えています。
添付ファイルの説明

-MS SQL Server でベース、テーブル、プロシージャ作成方法例としての SQL 形式のスクリプト

- MS SQL に履歴をロードするスクリプト

- DLL project

シンボルチャートに EA としてアタッチするために、そのティックを収集する必要があります。それは任意のタイムフレームにアタッチ可能です。
おわりに
別のソフトウェア製品と統合することは、MetaTrader 4 の機能性を広げ、自動トレーディングシステムのタスクと関数を効率的に分配することを可能にします。
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/1533





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索